From 21a5a4aef01bed3583c1b136e17613934351568d Mon Sep 17 00:00:00 2001 From: NOTPIES Date: Sun, 1 Mar 2026 20:29:13 -0300 Subject: [PATCH] Initial commit - LCEMP source code (assets excluded) --- .gitignore | 179 + Minecraft.Client/AbstractContainerScreen.cpp | 235 + Minecraft.Client/AbstractContainerScreen.h | 38 + Minecraft.Client/AbstractTexturePack.cpp | 399 + Minecraft.Client/AbstractTexturePack.h | 93 + Minecraft.Client/AchievementPopup.cpp | 151 + Minecraft.Client/AchievementPopup.h | 28 + Minecraft.Client/AchievementScreen.cpp | 426 + Minecraft.Client/AchievementScreen.h | 57 + Minecraft.Client/AllowAllCuller.cpp | 21 + Minecraft.Client/AllowAllCuller.h | 11 + Minecraft.Client/ArchiveFile.cpp | 215 + Minecraft.Client/ArchiveFile.h | 38 + Minecraft.Client/ArrowRenderer.cpp | 86 + Minecraft.Client/ArrowRenderer.h | 8 + Minecraft.Client/BlazeModel.cpp | 76 + Minecraft.Client/BlazeModel.h | 16 + Minecraft.Client/BlazeRenderer.cpp | 24 + Minecraft.Client/BlazeRenderer.h | 14 + Minecraft.Client/BoatModel.cpp | 51 + Minecraft.Client/BoatModel.h | 11 + Minecraft.Client/BoatRenderer.cpp | 41 + Minecraft.Client/BoatRenderer.h | 13 + Minecraft.Client/BookModel.cpp | 68 + Minecraft.Client/BookModel.h | 16 + Minecraft.Client/BreakingItemParticle.cpp | 64 + Minecraft.Client/BreakingItemParticle.h | 15 + Minecraft.Client/BubbleParticle.cpp | 41 + Minecraft.Client/BubbleParticle.h | 10 + Minecraft.Client/BufferedImage.cpp | 400 + Minecraft.Client/BufferedImage.h | 33 + Minecraft.Client/Button.cpp | 85 + Minecraft.Client/Button.h | 30 + Minecraft.Client/Camera.cpp | 124 + Minecraft.Client/Camera.h | 32 + Minecraft.Client/ChatScreen.cpp | 89 + Minecraft.Client/ChatScreen.h | 25 + Minecraft.Client/ChestModel.cpp | 43 + Minecraft.Client/ChestModel.h | 18 + Minecraft.Client/ChestRenderer.cpp | 105 + Minecraft.Client/ChestRenderer.h | 18 + Minecraft.Client/ChickenModel.cpp | 104 + Minecraft.Client/ChickenModel.h | 11 + Minecraft.Client/ChickenRenderer.cpp | 24 + Minecraft.Client/ChickenRenderer.h | 11 + Minecraft.Client/Chunk.cpp | 1045 + Minecraft.Client/Chunk.h | 87 + Minecraft.Client/ClientConnection.cpp | 3347 ++ Minecraft.Client/ClientConnection.h | 140 + Minecraft.Client/ClientConstants.cpp | 5 + Minecraft.Client/ClientConstants.h | 19 + Minecraft.Client/ClockTexture.cpp | 119 + Minecraft.Client/ClockTexture.h | 21 + Minecraft.Client/Common/App_Defines.h | 130 + Minecraft.Client/Common/App_enums.h | 913 + Minecraft.Client/Common/App_structs.h | 227 + .../Common/Audio/Consoles_SoundEngine.cpp | 38 + .../Common/Audio/Consoles_SoundEngine.h | 81 + Minecraft.Client/Common/Audio/SoundEngine.cpp | 1668 + Minecraft.Client/Common/Audio/SoundEngine.h | 168 + Minecraft.Client/Common/Audio/SoundNames.cpp | 165 + Minecraft.Client/Common/BuildVer.h | 57 + Minecraft.Client/Common/C4JMemoryPool.h | 176 + .../Common/C4JMemoryPoolAllocator.h | 113 + .../Common/Colours/ColourTable.cpp | 366 + Minecraft.Client/Common/Colours/ColourTable.h | 23 + Minecraft.Client/Common/CommonMedia.sln | 28 + Minecraft.Client/Common/CommonMedia.vcxproj | 115 + .../Common/CommonMedia.vcxproj.filters | 136 + Minecraft.Client/Common/ConsoleGameMode.cpp | 9 + Minecraft.Client/Common/ConsoleGameMode.h | 10 + Minecraft.Client/Common/Console_Awards_enum.h | 72 + Minecraft.Client/Common/Console_Debug_enum.h | 42 + Minecraft.Client/Common/Console_Utils.cpp | 40 + Minecraft.Client/Common/Consoles_App.cpp | 9539 ++++ Minecraft.Client/Common/Consoles_App.h | 911 + .../AddEnchantmentRuleDefinition.cpp | 70 + .../GameRules/AddEnchantmentRuleDefinition.h | 23 + .../GameRules/AddItemRuleDefinition.cpp | 127 + .../Common/GameRules/AddItemRuleDefinition.h | 30 + .../ApplySchematicRuleDefinition.cpp | 249 + .../GameRules/ApplySchematicRuleDefinition.h | 51 + .../Common/GameRules/BiomeOverride.cpp | 59 + .../Common/GameRules/BiomeOverride.h | 23 + .../GameRules/CollectItemRuleDefinition.cpp | 117 + .../GameRules/CollectItemRuleDefinition.h | 40 + .../GameRules/CompleteAllRuleDefinition.cpp | 66 + .../GameRules/CompleteAllRuleDefinition.h | 26 + .../GameRules/CompoundGameRuleDefinition.cpp | 118 + .../GameRules/CompoundGameRuleDefinition.h | 23 + .../Common/GameRules/ConsoleGameRules.h | 32 + .../GameRules/ConsoleGameRulesConstants.h | 119 + .../GameRules/ConsoleGenerateStructure.cpp | 181 + .../GameRules/ConsoleGenerateStructure.h | 38 + .../ConsoleGenerateStructureAction.h | 11 + .../Common/GameRules/ConsoleSchematicFile.cpp | 1020 + .../Common/GameRules/ConsoleSchematicFile.h | 90 + .../Common/GameRules/GameRule.cpp | 97 + Minecraft.Client/Common/GameRules/GameRule.h | 62 + .../Common/GameRules/GameRuleDefinition.cpp | 151 + .../Common/GameRules/GameRuleDefinition.h | 66 + .../Common/GameRules/GameRuleManager.cpp | 767 + .../Common/GameRules/GameRuleManager.h | 80 + .../Common/GameRules/GameRulesInstance.h | 24 + .../GameRules/LevelGenerationOptions.cpp | 514 + .../Common/GameRules/LevelGenerationOptions.h | 216 + .../Common/GameRules/LevelGenerators.cpp | 26 + .../Common/GameRules/LevelGenerators.h | 19 + .../Common/GameRules/LevelRules.cpp | 20 + .../Common/GameRules/LevelRules.h | 14 + .../Common/GameRules/LevelRuleset.cpp | 71 + .../Common/GameRules/LevelRuleset.h | 27 + .../GameRules/NamedAreaRuleDefinition.cpp | 84 + .../GameRules/NamedAreaRuleDefinition.h | 23 + .../Common/GameRules/StartFeature.cpp | 53 + .../Common/GameRules/StartFeature.h | 22 + .../GameRules/UpdatePlayerRuleDefinition.cpp | 171 + .../GameRules/UpdatePlayerRuleDefinition.h | 33 + .../GameRules/UseTileRuleDefinition.cpp | 82 + .../Common/GameRules/UseTileRuleDefinition.h | 24 + .../XboxStructureActionGenerateBox.cpp | 104 + .../XboxStructureActionGenerateBox.h | 26 + .../XboxStructureActionPlaceBlock.cpp | 72 + .../GameRules/XboxStructureActionPlaceBlock.h | 25 + .../XboxStructureActionPlaceContainer.cpp | 99 + .../XboxStructureActionPlaceContainer.h | 29 + .../XboxStructureActionPlaceSpawner.cpp | 69 + .../XboxStructureActionPlaceSpawner.h | 24 + .../Leaderboards/LeaderboardManager.cpp | 106 + .../Common/Leaderboards/LeaderboardManager.h | 268 + Minecraft.Client/Common/Minecraft_Macros.h | 42 + .../Common/Network/GameNetworkManager.cpp | 2006 + .../Common/Network/GameNetworkManager.h | 236 + .../Common/Network/NetworkPlayerInterface.h | 31 + .../Network/PlatformNetworkManagerInterface.h | 127 + .../Network/PlatformNetworkManagerStub.cpp | 859 + .../Network/PlatformNetworkManagerStub.h | 171 + Minecraft.Client/Common/Network/SessionInfo.h | 127 + Minecraft.Client/Common/Potion_Macros.h | 54 + .../Common/Telemetry/TelemetryManager.cpp | 450 + .../Common/Telemetry/TelemetryManager.h | 65 + Minecraft.Client/Common/Trial/TrialLevel.mcs | Bin 0 -> 3354946 bytes Minecraft.Client/Common/Trial/TrialMode.cpp | 9 + Minecraft.Client/Common/Trial/TrialMode.h | 10 + .../Common/Tutorial/AreaConstraint.cpp | 52 + .../Common/Tutorial/AreaConstraint.h | 24 + Minecraft.Client/Common/Tutorial/AreaHint.cpp | 49 + Minecraft.Client/Common/Tutorial/AreaHint.h | 25 + Minecraft.Client/Common/Tutorial/AreaTask.cpp | 69 + Minecraft.Client/Common/Tutorial/AreaTask.h | 24 + .../Common/Tutorial/ChangeStateConstraint.cpp | 136 + .../Common/Tutorial/ChangeStateConstraint.h | 37 + .../Common/Tutorial/ChoiceTask.cpp | 135 + Minecraft.Client/Common/Tutorial/ChoiceTask.h | 27 + .../Common/Tutorial/CompleteUsingItemTask.cpp | 37 + .../Common/Tutorial/CompleteUsingItemTask.h | 20 + .../Common/Tutorial/ControllerTask.cpp | 123 + .../Common/Tutorial/ControllerTask.h | 24 + .../Common/Tutorial/CraftTask.cpp | 66 + Minecraft.Client/Common/Tutorial/CraftTask.h | 25 + .../Common/Tutorial/DiggerItemHint.cpp | 76 + .../Common/Tutorial/DiggerItemHint.h | 18 + .../Common/Tutorial/EffectChangedTask.cpp | 31 + .../Common/Tutorial/EffectChangedTask.h | 19 + .../Common/Tutorial/FullTutorial.cpp | 653 + .../Common/Tutorial/FullTutorial.h | 21 + .../Tutorial/FullTutorialActiveTask.cpp | 26 + .../Common/Tutorial/FullTutorialActiveTask.h | 18 + .../Common/Tutorial/FullTutorialMode.cpp | 16 + .../Common/Tutorial/FullTutorialMode.h | 12 + Minecraft.Client/Common/Tutorial/InfoTask.cpp | 137 + Minecraft.Client/Common/Tutorial/InfoTask.h | 25 + .../Common/Tutorial/InputConstraint.cpp | 18 + .../Common/Tutorial/InputConstraint.h | 15 + .../Common/Tutorial/LookAtEntityHint.cpp | 25 + .../Common/Tutorial/LookAtEntityHint.h | 20 + .../Common/Tutorial/LookAtTileHint.cpp | 68 + .../Common/Tutorial/LookAtTileHint.h | 22 + .../Common/Tutorial/PickupTask.cpp | 17 + Minecraft.Client/Common/Tutorial/PickupTask.h | 26 + .../Common/Tutorial/ProcedureCompoundTask.cpp | 263 + .../Common/Tutorial/ProcedureCompoundTask.h | 36 + .../Common/Tutorial/ProgressFlagTask.cpp | 17 + .../Common/Tutorial/ProgressFlagTask.h | 25 + Minecraft.Client/Common/Tutorial/StatTask.cpp | 25 + Minecraft.Client/Common/Tutorial/StatTask.h | 18 + .../Common/Tutorial/StateChangeTask.h | 27 + .../Common/Tutorial/TakeItemHint.cpp | 45 + .../Common/Tutorial/TakeItemHint.h | 19 + Minecraft.Client/Common/Tutorial/Tutorial | Bin 0 -> 8973500 bytes Minecraft.Client/Common/Tutorial/Tutorial.cpp | 2160 + Minecraft.Client/Common/Tutorial/Tutorial.h | 199 + .../Common/Tutorial/TutorialConstraint.h | 41 + .../Common/Tutorial/TutorialConstraints.h | 4 + .../Common/Tutorial/TutorialEnum.h | 329 + .../Common/Tutorial/TutorialHint.cpp | 128 + .../Common/Tutorial/TutorialHint.h | 53 + .../Common/Tutorial/TutorialHints.h | 7 + .../Common/Tutorial/TutorialMessage.cpp | 23 + .../Common/Tutorial/TutorialMessage.h | 20 + .../Common/Tutorial/TutorialMode.cpp | 124 + .../Common/Tutorial/TutorialMode.h | 28 + .../Common/Tutorial/TutorialTask.cpp | 78 + .../Common/Tutorial/TutorialTask.h | 63 + .../Common/Tutorial/TutorialTasks.h | 16 + .../Common/Tutorial/UseItemTask.cpp | 25 + .../Common/Tutorial/UseItemTask.h | 20 + .../Common/Tutorial/UseTileTask.cpp | 40 + .../Common/Tutorial/UseTileTask.h | 24 + .../Common/Tutorial/XuiCraftingTask.cpp | 42 + .../Common/Tutorial/XuiCraftingTask.h | 36 + Minecraft.Client/Common/UI/IUIController.h | 77 + .../UI/IUIScene_AbstractContainerMenu.cpp | 1661 + .../UI/IUIScene_AbstractContainerMenu.h | 223 + .../Common/UI/IUIScene_AnvilMenu.cpp | 272 + .../Common/UI/IUIScene_AnvilMenu.h | 45 + .../Common/UI/IUIScene_BrewingMenu.cpp | 151 + .../Common/UI/IUIScene_BrewingMenu.h | 19 + .../Common/UI/IUIScene_ContainerMenu.cpp | 71 + .../Common/UI/IUIScene_ContainerMenu.h | 10 + .../Common/UI/IUIScene_CraftingMenu.cpp | 1400 + .../Common/UI/IUIScene_CraftingMenu.h | 119 + .../Common/UI/IUIScene_CreativeMenu.cpp | 1053 + .../Common/UI/IUIScene_CreativeMenu.h | 122 + .../Common/UI/IUIScene_DispenserMenu.cpp | 77 + .../Common/UI/IUIScene_DispenserMenu.h | 12 + .../Common/UI/IUIScene_EnchantingMenu.cpp | 185 + .../Common/UI/IUIScene_EnchantingMenu.h | 23 + .../Common/UI/IUIScene_FurnaceMenu.cpp | 141 + .../Common/UI/IUIScene_FurnaceMenu.h | 15 + .../Common/UI/IUIScene_InventoryMenu.cpp | 72 + .../Common/UI/IUIScene_InventoryMenu.h | 10 + .../Common/UI/IUIScene_PauseMenu.cpp | 691 + .../Common/UI/IUIScene_PauseMenu.h | 25 + .../Common/UI/IUIScene_StartGame.cpp | 379 + .../Common/UI/IUIScene_StartGame.h | 48 + .../Common/UI/IUIScene_TradingMenu.cpp | 387 + .../Common/UI/IUIScene_TradingMenu.h | 58 + Minecraft.Client/Common/UI/UI.h | 118 + Minecraft.Client/Common/UI/UIBitmapFont.cpp | 364 + Minecraft.Client/Common/UI/UIBitmapFont.h | 75 + .../Common/UI/UIComponent_Chat.cpp | 157 + Minecraft.Client/Common/UI/UIComponent_Chat.h | 66 + .../Common/UI/UIComponent_DebugUIConsole.cpp | 39 + .../Common/UI/UIComponent_DebugUIConsole.h | 49 + .../UI/UIComponent_DebugUIMarketingGuide.cpp | 33 + .../UI/UIComponent_DebugUIMarketingGuide.h | 34 + .../Common/UI/UIComponent_Logo.cpp | 30 + Minecraft.Client/Common/UI/UIComponent_Logo.h | 25 + .../Common/UI/UIComponent_MenuBackground.cpp | 103 + .../Common/UI/UIComponent_MenuBackground.h | 30 + .../Common/UI/UIComponent_Panorama.cpp | 144 + .../Common/UI/UIComponent_Panorama.h | 40 + .../UI/UIComponent_PressStartToPlay.cpp | 167 + .../Common/UI/UIComponent_PressStartToPlay.h | 60 + .../Common/UI/UIComponent_Tooltips.cpp | 501 + .../Common/UI/UIComponent_Tooltips.h | 110 + .../Common/UI/UIComponent_TutorialPopup.cpp | 539 + .../Common/UI/UIComponent_TutorialPopup.h | 101 + Minecraft.Client/Common/UI/UIControl.cpp | 153 + Minecraft.Client/Common/UI/UIControl.h | 92 + Minecraft.Client/Common/UI/UIControl_Base.cpp | 112 + Minecraft.Client/Common/UI/UIControl_Base.h | 30 + .../Common/UI/UIControl_BitmapIcon.cpp | 27 + .../Common/UI/UIControl_BitmapIcon.h | 14 + .../Common/UI/UIControl_Button.cpp | 68 + Minecraft.Client/Common/UI/UIControl_Button.h | 19 + .../Common/UI/UIControl_ButtonList.cpp | 197 + .../Common/UI/UIControl_ButtonList.h | 44 + .../Common/UI/UIControl_CheckBox.cpp | 109 + .../Common/UI/UIControl_CheckBox.h | 27 + .../Common/UI/UIControl_Cursor.cpp | 17 + Minecraft.Client/Common/UI/UIControl_Cursor.h | 11 + .../Common/UI/UIControl_DLCList.cpp | 69 + .../Common/UI/UIControl_DLCList.h | 17 + .../Common/UI/UIControl_DynamicLabel.cpp | 98 + .../Common/UI/UIControl_DynamicLabel.h | 25 + .../Common/UI/UIControl_EnchantmentBook.cpp | 140 + .../Common/UI/UIControl_EnchantmentBook.h | 33 + .../Common/UI/UIControl_EnchantmentButton.cpp | 205 + .../Common/UI/UIControl_EnchantmentButton.h | 55 + .../Common/UI/UIControl_HTMLLabel.cpp | 103 + .../Common/UI/UIControl_HTMLLabel.h | 27 + .../Common/UI/UIControl_Label.cpp | 53 + Minecraft.Client/Common/UI/UIControl_Label.h | 15 + .../Common/UI/UIControl_LeaderboardList.cpp | 238 + .../Common/UI/UIControl_LeaderboardList.h | 50 + .../Common/UI/UIControl_MinecraftPlayer.cpp | 93 + .../Common/UI/UIControl_MinecraftPlayer.h | 15 + .../Common/UI/UIControl_PlayerList.cpp | 65 + .../Common/UI/UIControl_PlayerList.h | 17 + .../Common/UI/UIControl_PlayerSkinPreview.cpp | 514 + .../Common/UI/UIControl_PlayerSkinPreview.h | 90 + .../Common/UI/UIControl_Progress.cpp | 84 + .../Common/UI/UIControl_Progress.h | 25 + .../Common/UI/UIControl_SaveList.cpp | 106 + .../Common/UI/UIControl_SaveList.h | 29 + .../Common/UI/UIControl_Slider.cpp | 119 + Minecraft.Client/Common/UI/UIControl_Slider.h | 32 + .../Common/UI/UIControl_SlotList.cpp | 93 + .../Common/UI/UIControl_SlotList.h | 28 + .../Common/UI/UIControl_SpaceIndicatorBar.cpp | 122 + .../Common/UI/UIControl_SpaceIndicatorBar.h | 33 + .../Common/UI/UIControl_TextInput.cpp | 83 + .../Common/UI/UIControl_TextInput.h | 22 + .../Common/UI/UIControl_TexturePackList.cpp | 145 + .../Common/UI/UIControl_TexturePackList.h | 27 + .../Common/UI/UIControl_Touch.cpp | 38 + Minecraft.Client/Common/UI/UIControl_Touch.h | 16 + Minecraft.Client/Common/UI/UIController.cpp | 3053 ++ Minecraft.Client/Common/UI/UIController.h | 369 + Minecraft.Client/Common/UI/UIEnums.h | 234 + Minecraft.Client/Common/UI/UIFontData.cpp | 341 + Minecraft.Client/Common/UI/UIFontData.h | 133 + Minecraft.Client/Common/UI/UIGroup.cpp | 421 + Minecraft.Client/Common/UI/UIGroup.h | 113 + Minecraft.Client/Common/UI/UILayer.cpp | 870 + Minecraft.Client/Common/UI/UILayer.h | 91 + Minecraft.Client/Common/UI/UIScene.cpp | 1248 + Minecraft.Client/Common/UI/UIScene.h | 270 + .../UI/UIScene_AbstractContainerMenu.cpp | 307 + .../Common/UI/UIScene_AbstractContainerMenu.h | 63 + .../Common/UI/UIScene_AnvilMenu.cpp | 400 + .../Common/UI/UIScene_AnvilMenu.h | 66 + .../Common/UI/UIScene_BrewingStandMenu.cpp | 309 + .../Common/UI/UIScene_BrewingStandMenu.h | 49 + .../Common/UI/UIScene_ConnectingProgress.cpp | 267 + .../Common/UI/UIScene_ConnectingProgress.h | 61 + .../Common/UI/UIScene_ContainerMenu.cpp | 223 + .../Common/UI/UIScene_ContainerMenu.h | 40 + .../Common/UI/UIScene_ControlsMenu.cpp | 336 + .../Common/UI/UIScene_ControlsMenu.h | 141 + .../Common/UI/UIScene_CraftingMenu.cpp | 769 + .../Common/UI/UIScene_CraftingMenu.h | 205 + .../Common/UI/UIScene_CreateWorldMenu.cpp | 1457 + .../Common/UI/UIScene_CreateWorldMenu.h | 115 + .../Common/UI/UIScene_CreativeMenu.cpp | 493 + .../Common/UI/UIScene_CreativeMenu.h | 90 + .../Common/UI/UIScene_Credits.cpp | 677 + Minecraft.Client/Common/UI/UIScene_Credits.h | 71 + .../Common/UI/UIScene_DLCMainMenu.cpp | 243 + .../Common/UI/UIScene_DLCMainMenu.h | 50 + .../Common/UI/UIScene_DLCOffersMenu.cpp | 923 + .../Common/UI/UIScene_DLCOffersMenu.h | 96 + .../Common/UI/UIScene_DeathMenu.cpp | 191 + .../Common/UI/UIScene_DeathMenu.h | 44 + .../UI/UIScene_DebugCreateSchematic.cpp | 216 + .../Common/UI/UIScene_DebugCreateSchematic.h | 73 + .../Common/UI/UIScene_DebugOptions.cpp | 96 + .../Common/UI/UIScene_DebugOptions.h | 49 + .../Common/UI/UIScene_DebugOverlay.cpp | 265 + .../Common/UI/UIScene_DebugOverlay.h | 65 + .../Common/UI/UIScene_DebugSetCamera.cpp | 158 + .../Common/UI/UIScene_DebugSetCamera.h | 69 + .../Common/UI/UIScene_DispenserMenu.cpp | 197 + .../Common/UI/UIScene_DispenserMenu.h | 40 + Minecraft.Client/Common/UI/UIScene_EULA.cpp | 145 + Minecraft.Client/Common/UI/UIScene_EULA.h | 45 + .../Common/UI/UIScene_EnchantingMenu.cpp | 284 + .../Common/UI/UIScene_EnchantingMenu.h | 54 + .../Common/UI/UIScene_EndPoem.cpp | 271 + Minecraft.Client/Common/UI/UIScene_EndPoem.h | 41 + .../Common/UI/UIScene_FullscreenProgress.cpp | 374 + .../Common/UI/UIScene_FullscreenProgress.h | 69 + .../Common/UI/UIScene_FurnaceMenu.cpp | 256 + .../Common/UI/UIScene_FurnaceMenu.h | 50 + Minecraft.Client/Common/UI/UIScene_HUD.cpp | 997 + Minecraft.Client/Common/UI/UIScene_HUD.h | 183 + .../Common/UI/UIScene_HelpAndOptionsMenu.cpp | 233 + .../Common/UI/UIScene_HelpAndOptionsMenu.h | 50 + .../Common/UI/UIScene_HowToPlay.cpp | 328 + .../Common/UI/UIScene_HowToPlay.h | 123 + .../Common/UI/UIScene_HowToPlayMenu.cpp | 205 + .../Common/UI/UIScene_HowToPlayMenu.h | 68 + .../UI/UIScene_InGameHostOptionsMenu.cpp | 104 + .../Common/UI/UIScene_InGameHostOptionsMenu.h | 38 + .../Common/UI/UIScene_InGameInfoMenu.cpp | 605 + .../Common/UI/UIScene_InGameInfoMenu.h | 62 + .../UI/UIScene_InGamePlayerOptionsMenu.cpp | 438 + .../UI/UIScene_InGamePlayerOptionsMenu.h | 90 + .../UI/UIScene_InGameSaveManagementMenu.cpp | 497 + .../UI/UIScene_InGameSaveManagementMenu.h | 104 + Minecraft.Client/Common/UI/UIScene_Intro.cpp | 166 + Minecraft.Client/Common/UI/UIScene_Intro.h | 52 + .../Common/UI/UIScene_InventoryMenu.cpp | 334 + .../Common/UI/UIScene_InventoryMenu.h | 51 + .../Common/UI/UIScene_JoinMenu.cpp | 586 + Minecraft.Client/Common/UI/UIScene_JoinMenu.h | 98 + .../Common/UI/UIScene_Keyboard.cpp | 181 + Minecraft.Client/Common/UI/UIScene_Keyboard.h | 79 + .../UI/UIScene_LaunchMoreOptionsMenu.cpp | 462 + .../Common/UI/UIScene_LaunchMoreOptionsMenu.h | 125 + .../Common/UI/UIScene_LeaderboardsMenu.cpp | 1045 + .../Common/UI/UIScene_LeaderboardsMenu.h | 143 + .../Common/UI/UIScene_LoadMenu.cpp | 1804 + Minecraft.Client/Common/UI/UIScene_LoadMenu.h | 131 + .../Common/UI/UIScene_LoadOrJoinMenu.cpp | 3531 ++ .../Common/UI/UIScene_LoadOrJoinMenu.h | 300 + .../Common/UI/UIScene_MainMenu.cpp | 2043 + Minecraft.Client/Common/UI/UIScene_MainMenu.h | 175 + .../Common/UI/UIScene_MessageBox.cpp | 161 + .../Common/UI/UIScene_MessageBox.h | 59 + .../Common/UI/UIScene_PauseMenu.cpp | 1483 + .../Common/UI/UIScene_PauseMenu.h | 112 + .../Common/UI/UIScene_QuadrantSignin.cpp | 291 + .../Common/UI/UIScene_QuadrantSignin.h | 110 + .../Common/UI/UIScene_ReinstallMenu.cpp | 110 + .../Common/UI/UIScene_ReinstallMenu.h | 47 + .../Common/UI/UIScene_SaveMessage.cpp | 182 + .../Common/UI/UIScene_SaveMessage.h | 51 + .../Common/UI/UIScene_SettingsAudioMenu.cpp | 116 + .../Common/UI/UIScene_SettingsAudioMenu.h | 38 + .../Common/UI/UIScene_SettingsControlMenu.cpp | 116 + .../Common/UI/UIScene_SettingsControlMenu.h | 37 + .../UI/UIScene_SettingsGraphicsMenu.cpp | 153 + .../Common/UI/UIScene_SettingsGraphicsMenu.h | 46 + .../Common/UI/UIScene_SettingsMenu.cpp | 168 + .../Common/UI/UIScene_SettingsMenu.h | 47 + .../Common/UI/UIScene_SettingsOptionsMenu.cpp | 253 + .../Common/UI/UIScene_SettingsOptionsMenu.h | 57 + .../Common/UI/UIScene_SettingsUIMenu.cpp | 183 + .../Common/UI/UIScene_SettingsUIMenu.h | 53 + .../Common/UI/UIScene_SignEntryMenu.cpp | 206 + .../Common/UI/UIScene_SignEntryMenu.h | 58 + .../Common/UI/UIScene_SkinSelectMenu.cpp | 1798 + .../Common/UI/UIScene_SkinSelectMenu.h | 189 + .../Common/UI/UIScene_TeleportMenu.cpp | 344 + .../Common/UI/UIScene_TeleportMenu.h | 51 + Minecraft.Client/Common/UI/UIScene_Timer.cpp | 32 + Minecraft.Client/Common/UI/UIScene_Timer.h | 28 + .../Common/UI/UIScene_TradingMenu.cpp | 268 + .../Common/UI/UIScene_TradingMenu.h | 78 + .../Common/UI/UIScene_TrialExitUpsell.cpp | 75 + .../Common/UI/UIScene_TrialExitUpsell.h | 31 + Minecraft.Client/Common/UI/UIStructs.h | 409 + Minecraft.Client/Common/UI/UITTFFont.cpp | 51 + Minecraft.Client/Common/UI/UITTFFont.h | 12 + .../Common/XUI/SlotProgressControl.cpp | 88 + .../Common/XUI/SlotProgressControl.h | 18 + .../Common/XUI/XUI_BasePlayer.cpp | 9 + Minecraft.Client/Common/XUI/XUI_BasePlayer.h | 13 + Minecraft.Client/Common/XUI/XUI_Chat.cpp | 71 + Minecraft.Client/Common/XUI/XUI_Chat.h | 59 + .../Common/XUI/XUI_ConnectingProgress.cpp | 216 + .../Common/XUI/XUI_ConnectingProgress.h | 55 + .../Common/XUI/XUI_Control_ComboBox.cpp | 98 + .../Common/XUI/XUI_Control_ComboBox.h | 53 + Minecraft.Client/Common/XUI/XUI_Controls.h | 26 + .../Common/XUI/XUI_Ctrl_4JEdit.cpp | 200 + Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.h | 44 + .../Common/XUI/XUI_Ctrl_4JIcon.cpp | 61 + Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.h | 25 + .../Common/XUI/XUI_Ctrl_4JList.cpp | 405 + Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.h | 78 + .../Common/XUI/XUI_Ctrl_BrewProgress.cpp | 27 + .../Common/XUI/XUI_Ctrl_BrewProgress.h | 19 + .../Common/XUI/XUI_Ctrl_BubblesProgress.cpp | 52 + .../Common/XUI/XUI_Ctrl_BubblesProgress.h | 19 + .../Common/XUI/XUI_Ctrl_BurnProgress.cpp | 29 + .../Common/XUI/XUI_Ctrl_BurnProgress.h | 19 + .../XUI/XUI_Ctrl_CraftIngredientSlot.cpp | 123 + .../Common/XUI/XUI_Ctrl_CraftIngredientSlot.h | 45 + .../Common/XUI/XUI_Ctrl_EnchantButton.cpp | 90 + .../Common/XUI/XUI_Ctrl_EnchantButton.h | 33 + .../Common/XUI/XUI_Ctrl_EnchantmentBook.cpp | 346 + .../Common/XUI/XUI_Ctrl_EnchantmentBook.h | 51 + .../XUI/XUI_Ctrl_EnchantmentButtonText.cpp | 185 + .../XUI/XUI_Ctrl_EnchantmentButtonText.h | 45 + .../Common/XUI/XUI_Ctrl_FireProgress.cpp | 29 + .../Common/XUI/XUI_Ctrl_FireProgress.h | 19 + .../Common/XUI/XUI_Ctrl_LoadingProgress.cpp | 21 + .../Common/XUI/XUI_Ctrl_LoadingProgress.h | 18 + .../Common/XUI/XUI_Ctrl_MinecraftPlayer.cpp | 190 + .../Common/XUI/XUI_Ctrl_MinecraftPlayer.h | 42 + .../XUI/XUI_Ctrl_MinecraftSkinPreview.cpp | 551 + .../XUI/XUI_Ctrl_MinecraftSkinPreview.h | 106 + .../Common/XUI/XUI_Ctrl_MinecraftSlot.cpp | 356 + .../Common/XUI/XUI_Ctrl_MinecraftSlot.h | 59 + .../Common/XUI/XUI_Ctrl_MobEffect.cpp | 71 + .../Common/XUI/XUI_Ctrl_MobEffect.h | 31 + .../Common/XUI/XUI_Ctrl_PassThroughList.cpp | 109 + .../Common/XUI/XUI_Ctrl_PassthroughList.h | 28 + .../Common/XUI/XUI_Ctrl_ProgressCtrlBase.cpp | 22 + .../Common/XUI/XUI_Ctrl_ProgressCtrlBase.h | 11 + .../Common/XUI/XUI_Ctrl_SliderWrapper.cpp | 174 + .../Common/XUI/XUI_Ctrl_SliderWrapper.h | 38 + .../Common/XUI/XUI_Ctrl_SlotItem.h | 37 + .../Common/XUI/XUI_Ctrl_SlotItemCtrlBase.cpp | 392 + .../Common/XUI/XUI_Ctrl_SlotItemCtrlBase.h | 78 + .../Common/XUI/XUI_Ctrl_SlotItemListItem.h | 38 + .../Common/XUI/XUI_Ctrl_SlotList.cpp | 231 + .../Common/XUI/XUI_Ctrl_SlotList.h | 73 + .../Common/XUI/XUI_Ctrl_SplashPulser.cpp | 94 + .../Common/XUI/XUI_Ctrl_SplashPulser.h | 36 + .../Common/XUI/XUI_CustomMessages.h | 193 + Minecraft.Client/Common/XUI/XUI_DLCOffers.cpp | 886 + Minecraft.Client/Common/XUI/XUI_DLCOffers.h | 136 + Minecraft.Client/Common/XUI/XUI_Death.cpp | 242 + Minecraft.Client/Common/XUI/XUI_Death.h | 52 + Minecraft.Client/Common/XUI/XUI_Debug.h | 53 + .../Common/XUI/XUI_DebugItemEditor.cpp | 118 + .../Common/XUI/XUI_DebugItemEditor.h | 57 + .../Common/XUI/XUI_DebugOverlay.cpp | 391 + .../Common/XUI/XUI_DebugOverlay.h | 72 + .../Common/XUI/XUI_DebugSchematicCreator.cpp | 178 + .../Common/XUI/XUI_DebugSchematicCreator.h | 49 + .../Common/XUI/XUI_DebugSetCamera.cpp | 152 + .../Common/XUI/XUI_DebugSetCamera.h | 54 + Minecraft.Client/Common/XUI/XUI_DebugTips.cpp | 73 + Minecraft.Client/Common/XUI/XUI_DebugTips.h | 38 + .../Common/XUI/XUI_FullscreenProgress.cpp | 375 + .../Common/XUI/XUI_FullscreenProgress.h | 68 + Minecraft.Client/Common/XUI/XUI_HUD.cpp | 464 + Minecraft.Client/Common/XUI/XUI_HUD.h | 129 + .../Common/XUI/XUI_HelpAndOptions.cpp | 462 + .../Common/XUI/XUI_HelpAndOptions.h | 70 + .../Common/XUI/XUI_HelpControls.cpp | 566 + .../Common/XUI/XUI_HelpControls.h | 115 + .../Common/XUI/XUI_HelpCredits.cpp | 688 + Minecraft.Client/Common/XUI/XUI_HelpCredits.h | 73 + .../Common/XUI/XUI_HelpHowToPlay.cpp | 238 + .../Common/XUI/XUI_HelpHowToPlay.h | 217 + Minecraft.Client/Common/XUI/XUI_Helper.h | 38 + .../Common/XUI/XUI_HowToPlayMenu.cpp | 232 + .../Common/XUI/XUI_HowToPlayMenu.h | 76 + .../Common/XUI/XUI_InGameHostOptions.cpp | 150 + .../Common/XUI/XUI_InGameHostOptions.h | 45 + .../Common/XUI/XUI_InGameInfo.cpp | 537 + Minecraft.Client/Common/XUI/XUI_InGameInfo.h | 84 + .../Common/XUI/XUI_InGamePlayerOptions.cpp | 499 + .../Common/XUI/XUI_InGamePlayerOptions.h | 96 + Minecraft.Client/Common/XUI/XUI_Intro.cpp | 153 + Minecraft.Client/Common/XUI/XUI_Intro.h | 44 + .../Common/XUI/XUI_Leaderboards.cpp | 1202 + .../Common/XUI/XUI_Leaderboards.h | 169 + .../Common/XUI/XUI_LoadSettings.cpp | 1686 + .../Common/XUI/XUI_LoadSettings.h | 154 + Minecraft.Client/Common/XUI/XUI_MainMenu.cpp | 1288 + Minecraft.Client/Common/XUI/XUI_MainMenu.h | 128 + .../Common/XUI/XUI_MultiGameCreate.cpp | 1397 + .../Common/XUI/XUI_MultiGameCreate.h | 118 + .../Common/XUI/XUI_MultiGameInfo.cpp | 392 + .../Common/XUI/XUI_MultiGameInfo.h | 85 + .../Common/XUI/XUI_MultiGameJoinLoad.cpp | 2767 ++ .../Common/XUI/XUI_MultiGameJoinLoad.h | 168 + .../XUI/XUI_MultiGameLaunchMoreOptions.cpp | 306 + .../XUI/XUI_MultiGameLaunchMoreOptions.h | 75 + .../Common/XUI/XUI_NewUpdateMessage.cpp | 90 + .../Common/XUI/XUI_NewUpdateMessage.h | 31 + .../Common/XUI/XUI_PartnernetPassword.cpp | 70 + .../Common/XUI/XUI_PartnernetPassword.h | 40 + Minecraft.Client/Common/XUI/XUI_PauseMenu.cpp | 1219 + Minecraft.Client/Common/XUI/XUI_PauseMenu.h | 89 + Minecraft.Client/Common/XUI/XUI_Reinstall.cpp | 339 + Minecraft.Client/Common/XUI/XUI_Reinstall.h | 63 + .../Common/XUI/XUI_SaveMessage.cpp | 76 + Minecraft.Client/Common/XUI/XUI_SaveMessage.h | 36 + .../XUI/XUI_Scene_AbstractContainer.cpp | 475 + .../Common/XUI/XUI_Scene_AbstractContainer.h | 83 + .../Common/XUI/XUI_Scene_Anvil.cpp | 242 + Minecraft.Client/Common/XUI/XUI_Scene_Anvil.h | 88 + .../Common/XUI/XUI_Scene_Base.cpp | 2243 + Minecraft.Client/Common/XUI/XUI_Scene_Base.h | 432 + .../Common/XUI/XUI_Scene_BrewingStand.cpp | 156 + .../Common/XUI/XUI_Scene_BrewingStand.h | 75 + .../Common/XUI/XUI_Scene_Container.cpp | 162 + .../Common/XUI/XUI_Scene_Container.h | 57 + .../Common/XUI/XUI_Scene_CraftingPanel.cpp | 636 + .../Common/XUI/XUI_Scene_CraftingPanel.h | 205 + .../Common/XUI/XUI_Scene_Enchant.cpp | 144 + .../Common/XUI/XUI_Scene_Enchant.h | 78 + .../Common/XUI/XUI_Scene_Furnace.cpp | 153 + .../Common/XUI/XUI_Scene_Furnace.h | 79 + .../Common/XUI/XUI_Scene_Inventory.cpp | 234 + .../Common/XUI/XUI_Scene_Inventory.h | 89 + .../XUI/XUI_Scene_Inventory_Creative.cpp | 209 + .../Common/XUI/XUI_Scene_Inventory_Creative.h | 104 + .../Common/XUI/XUI_Scene_Trading.cpp | 320 + .../Common/XUI/XUI_Scene_Trading.h | 128 + .../Common/XUI/XUI_Scene_Trap.cpp | 122 + Minecraft.Client/Common/XUI/XUI_Scene_Trap.h | 62 + Minecraft.Client/Common/XUI/XUI_Scene_Win.cpp | 302 + Minecraft.Client/Common/XUI/XUI_Scene_Win.h | 58 + .../Common/XUI/XUI_SettingsAll.cpp | 227 + Minecraft.Client/Common/XUI/XUI_SettingsAll.h | 59 + .../Common/XUI/XUI_SettingsAudio.cpp | 263 + .../Common/XUI/XUI_SettingsAudio.h | 53 + .../Common/XUI/XUI_SettingsControl.cpp | 241 + .../Common/XUI/XUI_SettingsControl.h | 52 + .../Common/XUI/XUI_SettingsGraphics.cpp | 333 + .../Common/XUI/XUI_SettingsGraphics.h | 60 + .../Common/XUI/XUI_SettingsOptions.cpp | 508 + .../Common/XUI/XUI_SettingsOptions.h | 67 + .../Common/XUI/XUI_SettingsUI.cpp | 376 + Minecraft.Client/Common/XUI/XUI_SettingsUI.h | 65 + Minecraft.Client/Common/XUI/XUI_SignEntry.cpp | 113 + Minecraft.Client/Common/XUI/XUI_SignEntry.h | 49 + .../Common/XUI/XUI_SkinSelect.cpp | 1444 + Minecraft.Client/Common/XUI/XUI_SkinSelect.h | 150 + .../Common/XUI/XUI_SocialPost.cpp | 147 + Minecraft.Client/Common/XUI/XUI_SocialPost.h | 59 + Minecraft.Client/Common/XUI/XUI_Teleport.cpp | 312 + Minecraft.Client/Common/XUI/XUI_Teleport.h | 64 + Minecraft.Client/Common/XUI/XUI_TextEntry.cpp | 172 + Minecraft.Client/Common/XUI/XUI_TextEntry.h | 64 + .../Common/XUI/XUI_TransferToXboxOne.cpp | 569 + .../Common/XUI/XUI_TransferToXboxOne.h | 88 + .../Common/XUI/XUI_TrialExitUpsell.cpp | 136 + .../Common/XUI/XUI_TrialExitUpsell.h | 46 + .../Common/XUI/XUI_TutorialPopup.cpp | 603 + .../Common/XUI/XUI_TutorialPopup.h | 78 + Minecraft.Client/Common/XUI/XUI_XZP_Icons.h | 20 + Minecraft.Client/Common/XUI/XUI_debug.cpp | 391 + Minecraft.Client/Common/xuiscene_base.h | 176 + Minecraft.Client/Common/zlib/adler32.c | 178 + Minecraft.Client/Common/zlib/compress.c | 81 + Minecraft.Client/Common/zlib/crc32.c | 425 + Minecraft.Client/Common/zlib/crc32.h | 441 + Minecraft.Client/Common/zlib/deflate.c | 1967 + Minecraft.Client/Common/zlib/deflate.h | 346 + Minecraft.Client/Common/zlib/gzclose.c | 25 + Minecraft.Client/Common/zlib/gzguts.h | 209 + Minecraft.Client/Common/zlib/gzlib.c | 634 + Minecraft.Client/Common/zlib/gzread.c | 594 + Minecraft.Client/Common/zlib/gzwrite.c | 577 + Minecraft.Client/Common/zlib/infback.c | 640 + Minecraft.Client/Common/zlib/inffast.c | 340 + Minecraft.Client/Common/zlib/inffast.h | 11 + Minecraft.Client/Common/zlib/inffixed.h | 94 + Minecraft.Client/Common/zlib/inflate.c | 1512 + Minecraft.Client/Common/zlib/inflate.h | 122 + Minecraft.Client/Common/zlib/inftrees.c | 306 + Minecraft.Client/Common/zlib/inftrees.h | 62 + Minecraft.Client/Common/zlib/trees.c | 1226 + Minecraft.Client/Common/zlib/trees.h | 128 + Minecraft.Client/Common/zlib/uncompr.c | 59 + Minecraft.Client/Common/zlib/zconf.h | 511 + Minecraft.Client/Common/zlib/zlib.h | 1768 + Minecraft.Client/Common/zlib/zutil.c | 324 + Minecraft.Client/Common/zlib/zutil.h | 253 + Minecraft.Client/CompassTexture.cpp | 142 + Minecraft.Client/CompassTexture.h | 25 + Minecraft.Client/ConfirmScreen.cpp | 55 + Minecraft.Client/ConfirmScreen.h | 23 + Minecraft.Client/ConnectScreen.cpp | 95 + Minecraft.Client/ConnectScreen.h | 24 + Minecraft.Client/ConsoleInput.cpp | 8 + Minecraft.Client/ConsoleInput.h | 12 + Minecraft.Client/ConsoleInputSource.h | 9 + Minecraft.Client/ContainerScreen.cpp | 40 + Minecraft.Client/ContainerScreen.h | 19 + Minecraft.Client/ControlsScreen.cpp | 80 + Minecraft.Client/ControlsScreen.h | 31 + Minecraft.Client/CowModel.cpp | 32 + Minecraft.Client/CowModel.h | 10 + Minecraft.Client/CowRenderer.cpp | 11 + Minecraft.Client/CowRenderer.h | 9 + Minecraft.Client/CraftingScreen.cpp | 34 + Minecraft.Client/CraftingScreen.h | 14 + Minecraft.Client/CreateWorldScreen.cpp | 183 + Minecraft.Client/CreateWorldScreen.h | 32 + Minecraft.Client/CreativeMode.cpp | 128 + Minecraft.Client/CreativeMode.h | 26 + Minecraft.Client/CreeperModel.cpp | 80 + Minecraft.Client/CreeperModel.h | 14 + Minecraft.Client/CreeperRenderer.cpp | 90 + Minecraft.Client/CreeperRenderer.h | 16 + Minecraft.Client/CritParticle.cpp | 61 + Minecraft.Client/CritParticle.h | 25 + Minecraft.Client/CritParticle2.cpp | 93 + Minecraft.Client/CritParticle2.h | 19 + Minecraft.Client/Cube.cpp | 113 + Minecraft.Client/Cube.h | 29 + Minecraft.Client/Culler.h | 11 + Minecraft.Client/DLCTexturePack.cpp | 623 + Minecraft.Client/DLCTexturePack.h | 72 + Minecraft.Client/DeathScreen.cpp | 67 + Minecraft.Client/DeathScreen.h | 14 + Minecraft.Client/DefaultRenderer.cpp | 11 + Minecraft.Client/DefaultRenderer.h | 8 + Minecraft.Client/DefaultTexturePack.cpp | 131 + Minecraft.Client/DefaultTexturePack.h | 33 + Minecraft.Client/DemoLevel.cpp | 16 + Minecraft.Client/DemoLevel.h | 16 + Minecraft.Client/DemoMode.cpp | 125 + Minecraft.Client/DemoMode.h | 27 + Minecraft.Client/DemoUser.cpp | 6 + Minecraft.Client/DemoUser.h | 8 + Minecraft.Client/DerivedServerLevel.cpp | 29 + Minecraft.Client/DerivedServerLevel.h | 12 + Minecraft.Client/DirtyChunkSorter.cpp | 26 + Minecraft.Client/DirtyChunkSorter.h | 14 + Minecraft.Client/DisconnectedScreen.cpp | 55 + Minecraft.Client/DisconnectedScreen.h | 23 + Minecraft.Client/DistanceChunkSorter.cpp | 24 + Minecraft.Client/DistanceChunkSorter.h | 13 + Minecraft.Client/DragonBreathParticle.cpp | 104 + Minecraft.Client/DragonBreathParticle.h | 20 + Minecraft.Client/DragonModel.cpp | 248 + Minecraft.Client/DragonModel.h | 35 + Minecraft.Client/DripParticle.cpp | 132 + Minecraft.Client/DripParticle.h | 22 + .../Achievements/AchievementManager.cpp | 15 + .../Durango/Achievements/AchievementManager.h | 8 + Minecraft.Client/Durango/ApplicationView.cpp | 346 + Minecraft.Client/Durango/ApplicationView.h | 44 + .../Durango/Autogenerated.appxmanifest | 194 + .../Durango/DurangoExtras/DurangoStubs.cpp | 128 + .../Durango/DurangoExtras/DurangoStubs.h | 9 + .../Durango/DurangoExtras/xcompress.h | 253 + Minecraft.Client/Durango/Durango_App.cpp | 799 + Minecraft.Client/Durango/Durango_App.h | 87 + .../Durango/Durango_Minecraft.cpp | 1173 + .../Durango/Durango_UIController.cpp | 195 + .../Durango/Durango_UIController.h | 30 + .../DurangoLeaderboardManager.cpp | 717 + .../Leaderboards/DurangoLeaderboardManager.h | 94 + .../Leaderboards/DurangoStatsDebugger.cpp | 487 + .../Leaderboards/DurangoStatsDebugger.h | 94 + .../Durango/Leaderboards/GameProgress.cpp | 107 + .../Durango/Leaderboards/GameProgress.h | 23 + Minecraft.Client/Durango/Minecraft_Macros.h | 42 + .../Durango/Network/ChatIntegrationLayer.cpp | 805 + .../Durango/Network/ChatIntegrationLayer.h | 244 + .../Durango/Network/DQRNetworkManager.cpp | 3093 ++ .../Durango/Network/DQRNetworkManager.h | 582 + .../DQRNetworkManager_FriendSessions.cpp | 591 + .../Durango/Network/DQRNetworkManager_Log.cpp | 303 + .../Network/DQRNetworkManager_SendReceive.cpp | 409 + .../Network/DQRNetworkManager_XRNSEvent.cpp | 651 + .../Durango/Network/DQRNetworkPlayer.cpp | 204 + .../Durango/Network/DQRNetworkPlayer.h | 65 + .../Durango/Network/NetworkPlayerDurango.cpp | 113 + .../Durango/Network/NetworkPlayerDurango.h | 39 + .../Durango/Network/PartyController.cpp | 1205 + .../Durango/Network/PartyController.h | 74 + .../Network/PlatformNetworkManagerDurango.cpp | 940 + .../Network/PlatformNetworkManagerDurango.h | 168 + Minecraft.Client/Durango/Network/base64.cpp | 156 + Minecraft.Client/Durango/Network/base64.h | 6 + Minecraft.Client/Durango/PresenceIds.h | 27 + Minecraft.Client/Durango/Resource.h | 31 + .../Events-XBLA.8-149E11AEEvents.h | 1216 + .../ServiceConfig/HelpDocument/index.html | 184 + .../ServiceConfig/HelpDocument/main.css | 279 + .../ServiceConfig/HelpDocument/mobile.css | 160 + .../ServiceConfig/HelpDocument/skin.css | 51 + .../ServiceConfig/HelpDocument/snapped.css | 53 + .../ServiceConfig/HelpDocument/tablet.css | 117 + .../Durango/ServiceConfig/MakeZips.py | 62 + .../ServiceConfig/loc/de-DE/index.html | 170 + .../ServiceConfig/loc/en-GB/index.html | 170 + .../ServiceConfig/loc/es-ES/index.html | 170 + .../ServiceConfig/loc/fr-FR/index.html | 170 + .../ServiceConfig/loc/it-IT/index.html | 170 + .../ServiceConfig/loc/ja-JP/index.html | 170 + .../ServiceConfig/loc/ko-KR/index.html | 170 + .../ServiceConfig/loc/pt-BR/index.html | 170 + .../ServiceConfig/loc/pt-PT/index.html | 170 + .../ServiceConfig/loc/zh-CHT/index.html | 170 + .../Durango/Social/SocialManager.h | 137 + Minecraft.Client/Durango/XML/ATGXmlParser.cpp | 968 + Minecraft.Client/Durango/XML/ATGXmlParser.h | 156 + .../Durango/XML/xmlFilesCallback.h | 337 + Minecraft.Client/Durango/XboxGameMode.cpp | 9 + Minecraft.Client/Durango/XboxGameMode.h | 10 + Minecraft.Client/Durango/Xbox_Awards_enum.h | 46 + Minecraft.Client/Durango/Xbox_BuildVer.h | 53 + Minecraft.Client/Durango/Xbox_Debug_enum.h | 36 + Minecraft.Client/Durango/Xbox_Utils.cpp | 40 + Minecraft.Client/Durango/manifest.xml | 194 + Minecraft.Client/Durango/targetver.h | 8 + Minecraft.Client/EchantmentTableParticle.cpp | 71 + Minecraft.Client/EchantmentTableParticle.h | 21 + Minecraft.Client/EditBox.cpp | 110 + Minecraft.Client/EditBox.h | 36 + Minecraft.Client/EnchantTableRenderer.cpp | 59 + Minecraft.Client/EnchantTableRenderer.h | 19 + Minecraft.Client/EnderChestRenderer.cpp | 52 + Minecraft.Client/EnderChestRenderer.h | 13 + Minecraft.Client/EnderCrystalModel.cpp | 44 + Minecraft.Client/EnderCrystalModel.h | 18 + Minecraft.Client/EnderCrystalRenderer.cpp | 33 + Minecraft.Client/EnderCrystalRenderer.h | 17 + Minecraft.Client/EnderDragonRenderer.cpp | 267 + Minecraft.Client/EnderDragonRenderer.h | 36 + Minecraft.Client/EnderParticle.cpp | 94 + Minecraft.Client/EnderParticle.h | 21 + Minecraft.Client/EndermanModel.cpp | 121 + Minecraft.Client/EndermanModel.h | 13 + Minecraft.Client/EndermanRenderer.cpp | 107 + Minecraft.Client/EndermanRenderer.h | 22 + Minecraft.Client/EntityRenderDispatcher.cpp | 280 + Minecraft.Client/EntityRenderDispatcher.h | 49 + Minecraft.Client/EntityRenderer.cpp | 410 + Minecraft.Client/EntityRenderer.h | 65 + Minecraft.Client/EntityTileRenderer.cpp | 24 + Minecraft.Client/EntityTileRenderer.h | 19 + Minecraft.Client/EntityTracker.cpp | 229 + Minecraft.Client/EntityTracker.h | 36 + Minecraft.Client/ErrorScreen.cpp | 27 + Minecraft.Client/ErrorScreen.h | 14 + Minecraft.Client/ExperienceOrbRenderer.cpp | 91 + Minecraft.Client/ExperienceOrbRenderer.h | 17 + Minecraft.Client/ExplodeParticle.cpp | 62 + Minecraft.Client/ExplodeParticle.h | 11 + Minecraft.Client/Extrax64Stubs.cpp | 755 + Minecraft.Client/FallingTileRenderer.cpp | 56 + Minecraft.Client/FallingTileRenderer.h | 14 + Minecraft.Client/FileTexturePack.cpp | 86 + Minecraft.Client/FileTexturePack.h | 32 + Minecraft.Client/FireballRenderer.cpp | 109 + Minecraft.Client/FireballRenderer.h | 17 + Minecraft.Client/FishingHookRenderer.cpp | 101 + Minecraft.Client/FishingHookRenderer.h | 8 + Minecraft.Client/FlameParticle.cpp | 73 + Minecraft.Client/FlameParticle.h | 17 + Minecraft.Client/FolderTexturePack.cpp | 110 + Minecraft.Client/FolderTexturePack.h | 26 + Minecraft.Client/Font.cpp | 616 + Minecraft.Client/Font.h | 83 + Minecraft.Client/FootstepParticle.cpp | 63 + Minecraft.Client/FootstepParticle.h | 19 + Minecraft.Client/Frustum.cpp | 149 + Minecraft.Client/Frustum.h | 29 + Minecraft.Client/FrustumCuller.cpp | 29 + Minecraft.Client/FrustumCuller.h | 16 + Minecraft.Client/FrustumData.cpp | 90 + Minecraft.Client/FrustumData.h | 35 + Minecraft.Client/FurnaceScreen.cpp | 39 + Minecraft.Client/FurnaceScreen.h | 17 + Minecraft.Client/GameMode.cpp | 182 + Minecraft.Client/GameMode.h | 59 + Minecraft.Client/GameRenderer.cpp | 2169 + Minecraft.Client/GameRenderer.h | 171 + Minecraft.Client/GhastModel.cpp | 59 + Minecraft.Client/GhastModel.h | 14 + Minecraft.Client/GhastRenderer.cpp | 21 + Minecraft.Client/GhastRenderer.h | 11 + Minecraft.Client/GiantMobRenderer.cpp | 12 + Minecraft.Client/GiantMobRenderer.h | 14 + Minecraft.Client/Gui.cpp | 1530 + Minecraft.Client/Gui.h | 68 + Minecraft.Client/GuiComponent.cpp | 136 + Minecraft.Client/GuiComponent.h | 19 + Minecraft.Client/GuiMessage.cpp | 8 + Minecraft.Client/GuiMessage.h | 10 + Minecraft.Client/GuiParticle.cpp | 60 + Minecraft.Client/GuiParticle.h | 25 + Minecraft.Client/GuiParticles.cpp | 56 + Minecraft.Client/GuiParticles.h | 19 + Minecraft.Client/HeartParticle.cpp | 66 + Minecraft.Client/HeartParticle.h | 19 + Minecraft.Client/HttpTexture.cpp | 12 + Minecraft.Client/HttpTexture.h | 14 + Minecraft.Client/HttpTextureProcessor.h | 8 + Minecraft.Client/HugeExplosionParticle.cpp | 82 + Minecraft.Client/HugeExplosionParticle.h | 20 + .../HugeExplosionSeedParticle.cpp | 37 + Minecraft.Client/HugeExplosionSeedParticle.h | 17 + Minecraft.Client/HumanoidMobRenderer.cpp | 150 + Minecraft.Client/HumanoidMobRenderer.h | 22 + Minecraft.Client/HumanoidModel.cpp | 463 + Minecraft.Client/HumanoidModel.h | 65 + Minecraft.Client/InBedChatScreen.cpp | 70 + Minecraft.Client/InBedChatScreen.h | 20 + Minecraft.Client/Input.cpp | 187 + Minecraft.Client/Input.h | 22 + Minecraft.Client/InventoryScreen.cpp | 96 + Minecraft.Client/InventoryScreen.h | 20 + Minecraft.Client/ItemFrameRenderer.cpp | 184 + Minecraft.Client/ItemFrameRenderer.h | 17 + Minecraft.Client/ItemInHandRenderer.cpp | 878 + Minecraft.Client/ItemInHandRenderer.h | 40 + Minecraft.Client/ItemRenderer.cpp | 741 + Minecraft.Client/ItemRenderer.h | 52 + Minecraft.Client/ItemSpriteRenderer.cpp | 79 + Minecraft.Client/ItemSpriteRenderer.h | 18 + Minecraft.Client/JoinMultiplayerScreen.cpp | 128 + Minecraft.Client/JoinMultiplayerScreen.h | 26 + Minecraft.Client/KeyMapping.cpp | 8 + Minecraft.Client/KeyMapping.h | 10 + Minecraft.Client/KeyboardMouseInput.cpp | 294 + Minecraft.Client/KeyboardMouseInput.h | 105 + Minecraft.Client/LargeChestModel.cpp | 29 + Minecraft.Client/LargeChestModel.h | 9 + Minecraft.Client/LavaParticle.cpp | 69 + Minecraft.Client/LavaParticle.h | 16 + Minecraft.Client/LavaSlimeModel.cpp | 71 + Minecraft.Client/LavaSlimeModel.h | 15 + Minecraft.Client/LavaSlimeRenderer.cpp | 36 + Minecraft.Client/LavaSlimeRenderer.h | 17 + Minecraft.Client/LevelRenderer.cpp | 3644 ++ Minecraft.Client/LevelRenderer.h | 277 + Minecraft.Client/Lighting.cpp | 65 + Minecraft.Client/Lighting.h | 16 + Minecraft.Client/LightningBoltRenderer.cpp | 97 + Minecraft.Client/LightningBoltRenderer.h | 8 + Minecraft.Client/LocalPlayer.cpp | 1616 + Minecraft.Client/LocalPlayer.h | 199 + Minecraft.Client/MemTexture.cpp | 33 + Minecraft.Client/MemTexture.h | 17 + Minecraft.Client/MemTextureProcessor.h | 8 + Minecraft.Client/MemoryTracker.cpp | 70 + Minecraft.Client/MemoryTracker.h | 28 + Minecraft.Client/MinecartModel.cpp | 57 + Minecraft.Client/MinecartModel.h | 13 + Minecraft.Client/MinecartRenderer.cpp | 106 + Minecraft.Client/MinecartRenderer.h | 12 + Minecraft.Client/Minecraft.Client.vcxproj | 36842 ++++++++++++++++ .../Minecraft.Client.vcxproj.filters | 6023 +++ Minecraft.Client/Minecraft.cpp | 4983 +++ Minecraft.Client/Minecraft.h | 347 + Minecraft.Client/MinecraftServer.cpp | 1685 + Minecraft.Client/MinecraftServer.h | 245 + Minecraft.Client/Minimap.cpp | 262 + Minecraft.Client/Minimap.h | 35 + Minecraft.Client/MobRenderer.cpp | 515 + Minecraft.Client/MobRenderer.h | 46 + .../MobSkinMemTextureProcessor.cpp | 72 + Minecraft.Client/MobSkinMemTextureProcessor.h | 16 + Minecraft.Client/MobSkinTextureProcessor.cpp | 71 + Minecraft.Client/MobSkinTextureProcessor.h | 16 + Minecraft.Client/MobSpawnerRenderer.cpp | 30 + Minecraft.Client/MobSpawnerRenderer.h | 11 + Minecraft.Client/Model.cpp | 23 + Minecraft.Client/Model.h | 34 + Minecraft.Client/ModelPart.cpp | 322 + Minecraft.Client/ModelPart.h | 62 + Minecraft.Client/MultiPlayerChunkCache.cpp | 306 + Minecraft.Client/MultiPlayerChunkCache.h | 47 + Minecraft.Client/MultiPlayerGameMode.cpp | 487 + Minecraft.Client/MultiPlayerGameMode.h | 67 + Minecraft.Client/MultiPlayerLevel.cpp | 913 + Minecraft.Client/MultiPlayerLevel.h | 102 + Minecraft.Client/MultiPlayerLocalPlayer.cpp | 369 + Minecraft.Client/MultiPlayerLocalPlayer.h | 73 + Minecraft.Client/MushroomCowRenderer.cpp | 50 + Minecraft.Client/MushroomCowRenderer.h | 14 + Minecraft.Client/NameEntryScreen.cpp | 78 + Minecraft.Client/NameEntryScreen.h | 27 + Minecraft.Client/NetherPortalParticle.cpp | 99 + Minecraft.Client/NetherPortalParticle.h | 21 + .../Network Implementation Notes.txt | 45 + Minecraft.Client/NoteParticle.cpp | 87 + Minecraft.Client/NoteParticle.h | 16 + Minecraft.Client/OffsettedRenderList.cpp | 65 + Minecraft.Client/OffsettedRenderList.h | 21 + Minecraft.Client/Options.cpp | 525 + Minecraft.Client/Options.h | 132 + Minecraft.Client/OptionsScreen.cpp | 77 + Minecraft.Client/OptionsScreen.h | 23 + Minecraft.Client/Orbis/Assert/assert.h | 20 + .../Leaderboards/OrbisLeaderboardManager.cpp | 1081 + .../Leaderboards/OrbisLeaderboardManager.h | 109 + .../Orbis/Leaderboards/base64.cpp | 131 + Minecraft.Client/Orbis/Leaderboards/base64.h | 7 + .../MinecraftPronunciation.xml | 46 + .../MinecraftPronunciation/pronunciation.xml | 13 + Minecraft.Client/Orbis/Minecraft_Macros.h | 41 + .../Orbis/Network/Orbis_NPToolkit.cpp | 490 + .../Orbis/Network/Orbis_NPToolkit.h | 34 + .../Network/PsPlusUpsellWrapper_Orbis.cpp | 54 + .../Orbis/Network/PsPlusUpsellWrapper_Orbis.h | 20 + .../Orbis/Network/SQRNetworkManager_Orbis.cpp | 4155 ++ .../Orbis/Network/SQRNetworkManager_Orbis.h | 355 + .../Orbis/Network/SonyCommerce_Orbis.cpp | 1314 + .../Orbis/Network/SonyCommerce_Orbis.h | 182 + .../Orbis/Network/SonyHttp_Orbis.cpp | 285 + .../Orbis/Network/SonyHttp_Orbis.h | 26 + .../Orbis/Network/SonyRemoteStorage_Orbis.cpp | 371 + .../Orbis/Network/SonyRemoteStorage_Orbis.h | 42 + .../Network/SonyVoiceChatParty_Orbis.cpp | 355 + .../Orbis/Network/SonyVoiceChatParty_Orbis.h | 111 + .../Orbis/Network/SonyVoiceChat_Orbis.cpp | 1105 + .../Orbis/Network/SonyVoiceChat_Orbis.h | 215 + .../Orbis/OrbisExtras/OrbisMaths.h | 11 + .../Orbis/OrbisExtras/OrbisStubs.cpp | 790 + .../Orbis/OrbisExtras/OrbisStubs.h | 422 + .../Orbis/OrbisExtras/OrbisTypes.h | 176 + .../Orbis/OrbisExtras/ShutdownManager.h | 47 + .../Orbis/OrbisExtras/TLSStorage.cpp | 71 + .../Orbis/OrbisExtras/TLSStorage.h | 20 + Minecraft.Client/Orbis/OrbisExtras/winerror.h | 22031 +++++++++ Minecraft.Client/Orbis/Orbis_App.cpp | 1281 + Minecraft.Client/Orbis/Orbis_App.h | 221 + Minecraft.Client/Orbis/Orbis_Minecraft.cpp | 1698 + Minecraft.Client/Orbis/Orbis_PlayerUID.cpp | 217 + Minecraft.Client/Orbis/Orbis_PlayerUID.h | 85 + Minecraft.Client/Orbis/Orbis_UIController.cpp | 284 + Minecraft.Client/Orbis/Orbis_UIController.h | 32 + Minecraft.Client/Orbis/Social/SocialManager.h | 137 + Minecraft.Client/Orbis/XML/ATGXmlParser.h | 156 + Minecraft.Client/Orbis/Xbox_BuildVer.h | 53 + Minecraft.Client/Orbis/min/min.xml | 46 + Minecraft.Client/Orbis/min/pronunciation.xml | 29 + Minecraft.Client/Orbis/ps4__np_conf.h | 117 + Minecraft.Client/Orbis/user_malloc.cpp | 192 + .../Orbis/user_malloc_for_tls.cpp | 114 + Minecraft.Client/Orbis/user_new.cpp | 125 + Minecraft.Client/OzelotModel.cpp | 248 + Minecraft.Client/OzelotModel.h | 43 + Minecraft.Client/OzelotRenderer.cpp | 24 + Minecraft.Client/OzelotRenderer.h | 14 + Minecraft.Client/PS3/Assert/assert.h | 17 + .../PS3/Audio/PS3_SoundEngine.cpp | 117 + .../PS3/GameConfig/Minecraft.spa.h | 675 + .../Leaderboards/PS3LeaderboardManager.cpp | 1048 + .../PS3/Leaderboards/PS3LeaderboardManager.h | 110 + Minecraft.Client/PS3/Leaderboards/base64.cpp | 131 + Minecraft.Client/PS3/Leaderboards/base64.h | 7 + Minecraft.Client/PS3/Minecraft_Macros.h | 42 + .../PS3/Network/SQRNetworkManager_PS3.cpp | 3624 ++ .../PS3/Network/SQRNetworkManager_PS3.h | 300 + .../PS3/Network/SonyCommerce_PS3.cpp | 1513 + .../PS3/Network/SonyCommerce_PS3.h | 180 + Minecraft.Client/PS3/Network/SonyHttp_PS3.cpp | 289 + Minecraft.Client/PS3/Network/SonyHttp_PS3.h | 25 + .../PS3/Network/SonyRemoteStorage_PS3.cpp | 518 + .../PS3/Network/SonyRemoteStorage_PS3.h | 64 + .../PS3/Network/SonyVoiceChat.cpp | 764 + Minecraft.Client/PS3/Network/SonyVoiceChat.h | 157 + .../PS3/PS3Extras/C4JSpursJob.cpp | 409 + Minecraft.Client/PS3/PS3Extras/C4JSpursJob.h | 205 + .../PS3/PS3Extras/C4JThread_SPU.cpp | 136 + .../PS3/PS3Extras/C4JThread_SPU.h | 31 + Minecraft.Client/PS3/PS3Extras/EdgeZLib.cpp | 419 + Minecraft.Client/PS3/PS3Extras/EdgeZLib.h | 13 + Minecraft.Client/PS3/PS3Extras/PS3Maths.h | 11 + Minecraft.Client/PS3/PS3Extras/PS3Strings.cpp | 31 + Minecraft.Client/PS3/PS3Extras/PS3Strings.h | 3 + Minecraft.Client/PS3/PS3Extras/Ps3Stubs.cpp | 788 + Minecraft.Client/PS3/PS3Extras/Ps3Stubs.h | 431 + Minecraft.Client/PS3/PS3Extras/Ps3Types.h | 257 + .../PS3/PS3Extras/ShutdownManager.cpp | 204 + .../PS3/PS3Extras/ShutdownManager.h | 47 + Minecraft.Client/PS3/PS3Extras/TLSStorage.cpp | 72 + Minecraft.Client/PS3/PS3Extras/TLSStorage.h | 25 + Minecraft.Client/PS3/PS3Extras/winerror.h | 22031 +++++++++ Minecraft.Client/PS3/PS3_App.cpp | 1257 + Minecraft.Client/PS3/PS3_App.h | 217 + Minecraft.Client/PS3/PS3_Minecraft.cpp | 1577 + Minecraft.Client/PS3/PS3_PlayerUID.cpp | 197 + Minecraft.Client/PS3/PS3_PlayerUID.h | 72 + Minecraft.Client/PS3/PS3_UIController.cpp | 199 + Minecraft.Client/PS3/PS3_UIController.h | 28 + Minecraft.Client/PS3/Resource.h | 31 + Minecraft.Client/PS3/Social/SocialManager.h | 135 + Minecraft.Client/PS3/XML/ATGXmlParser.h | 156 + Minecraft.Client/PS3/XML/xmlFilesCallback.h | 232 + Minecraft.Client/PS3/XboxGameMode.cpp | 9 + Minecraft.Client/PS3/XboxGameMode.h | 10 + Minecraft.Client/PS3/Xbox_Awards_enum.h | 46 + Minecraft.Client/PS3/Xbox_BuildVer.h | 53 + Minecraft.Client/PS3/Xbox_Debug_enum.h | 36 + Minecraft.Client/PS3/Xbox_Minecraft.cpp | 1192 + Minecraft.Client/PS3/Xbox_Utils.cpp | 40 + Minecraft.Client/PS3/targetver.h | 8 + Minecraft.Client/PSVita/Assert/assert.h | 20 + .../PSVita/GameConfig/Minecraft.spa.h | 701 + Minecraft.Client/PSVita/GameConfig/rename.py | 69 + .../Leaderboards/PSVitaLeaderboardManager.cpp | 1070 + .../Leaderboards/PSVitaLeaderboardManager.h | 108 + .../PSVita/Leaderboards/base64.cpp | 131 + Minecraft.Client/PSVita/Leaderboards/base64.h | 7 + .../PSVita/Network/PSVita_NPToolkit.cpp | 491 + .../PSVita/Network/PSVita_NPToolkit.h | 32 + .../Network/SQRNetworkManager_AdHoc_Vita.cpp | 3119 ++ .../Network/SQRNetworkManager_AdHoc_Vita.h | 352 + .../PSVita/Network/SQRNetworkManager_Vita.cpp | 4080 ++ .../PSVita/Network/SQRNetworkManager_Vita.h | 324 + .../PSVita/Network/SonyCommerce_Vita.cpp | 1519 + .../PSVita/Network/SonyCommerce_Vita.h | 204 + .../PSVita/Network/SonyHttp_Vita.cpp | 271 + .../PSVita/Network/SonyHttp_Vita.h | 26 + .../PSVita/Network/SonyRemoteStorage_Vita.cpp | 398 + .../PSVita/Network/SonyRemoteStorage_Vita.h | 43 + .../PSVita/Network/SonyVoiceChat_Vita.cpp | 1092 + .../PSVita/Network/SonyVoiceChat_Vita.h | 222 + Minecraft.Client/PSVita/PSVitaExtras/Conf.h | 84 + .../PSVita/PSVitaExtras/CustomMap.cpp | 132 + .../PSVita/PSVitaExtras/CustomMap.h | 43 + .../PSVita/PSVitaExtras/CustomSet.cpp | 130 + .../PSVita/PSVitaExtras/CustomSet.h | 42 + .../PSVita/PSVitaExtras/PSVitaMaths.h | 11 + .../PSVita/PSVitaExtras/PSVitaStrings.cpp | 51 + .../PSVita/PSVitaExtras/PSVitaStrings.h | 3 + .../PSVita/PSVitaExtras/PSVitaStubs.h | 468 + .../PSVita/PSVitaExtras/PSVitaTLSStorage.cpp | 237 + .../PSVita/PSVitaExtras/PSVitaTLSStorage.h | 16 + .../PSVita/PSVitaExtras/PSVitaTypes.h | 176 + .../PSVita/PSVitaExtras/PsVitaStubs.cpp | 1045 + .../PSVita/PSVitaExtras/ShutdownManager.cpp | 204 + .../PSVita/PSVitaExtras/ShutdownManager.h | 47 + .../PSVita/PSVitaExtras/TLSStorage.cpp | 72 + .../PSVita/PSVitaExtras/TLSStorage.h | 25 + .../PSVita/PSVitaExtras/libdivide.h | 1302 + .../PSVita/PSVitaExtras/user_malloc.c | 390 + .../PSVita/PSVitaExtras/user_malloc_for_tls.c | 103 + .../PSVita/PSVitaExtras/user_new.cpp | 131 + Minecraft.Client/PSVita/PSVitaExtras/zconf.h | 511 + Minecraft.Client/PSVita/PSVitaExtras/zlib.h | 1768 + Minecraft.Client/PSVita/PSVita_App.cpp | 1672 + Minecraft.Client/PSVita/PSVita_App.h | 242 + Minecraft.Client/PSVita/PSVita_Minecraft.cpp | 1084 + Minecraft.Client/PSVita/PSVita_PlayerUID.cpp | 217 + Minecraft.Client/PSVita/PSVita_PlayerUID.h | 75 + .../PSVita/PSVita_UIController.cpp | 240 + Minecraft.Client/PSVita/PSVita_UIController.h | 31 + .../PSVita/Social/SocialManager.h | 137 + Minecraft.Client/PSVita/XML/ATGXmlParser.h | 156 + .../PSVita/configuration.psp2path | 40 + Minecraft.Client/PaintingRenderer.cpp | 131 + Minecraft.Client/PaintingRenderer.h | 19 + Minecraft.Client/Particle.cpp | 246 + Minecraft.Client/Particle.h | 53 + Minecraft.Client/ParticleEngine.cpp | 212 + Minecraft.Client/ParticleEngine.h | 44 + Minecraft.Client/PauseScreen.cpp | 99 + Minecraft.Client/PauseScreen.h | 18 + Minecraft.Client/PendingConnection.cpp | 297 + Minecraft.Client/PendingConnection.h | 48 + Minecraft.Client/PigModel.cpp | 20 + Minecraft.Client/PigModel.h | 10 + Minecraft.Client/PigRenderer.cpp | 24 + Minecraft.Client/PigRenderer.h | 13 + Minecraft.Client/PistonPieceRenderer.cpp | 68 + Minecraft.Client/PistonPieceRenderer.h | 14 + Minecraft.Client/PlayerChunkMap.cpp | 800 + Minecraft.Client/PlayerChunkMap.h | 105 + Minecraft.Client/PlayerCloudParticle.cpp | 68 + Minecraft.Client/PlayerCloudParticle.h | 15 + Minecraft.Client/PlayerConnection.cpp | 1717 + Minecraft.Client/PlayerConnection.h | 138 + Minecraft.Client/PlayerInfo.h | 15 + Minecraft.Client/PlayerList.cpp | 1487 + Minecraft.Client/PlayerList.h | 127 + Minecraft.Client/PlayerRenderer.cpp | 585 + Minecraft.Client/PlayerRenderer.h | 42 + Minecraft.Client/Polygon.cpp | 80 + Minecraft.Client/Polygon.h | 22 + Minecraft.Client/PreStitchedTextureMap.cpp | 853 + Minecraft.Client/PreStitchedTextureMap.h | 51 + Minecraft.Client/ProgressRenderer.cpp | 214 + Minecraft.Client/ProgressRenderer.h | 43 + Minecraft.Client/QuadrupedModel.cpp | 131 + Minecraft.Client/QuadrupedModel.h | 13 + Minecraft.Client/ReadMe.txt | 27 + Minecraft.Client/ReceivingLevelScreen.cpp | 47 + Minecraft.Client/ReceivingLevelScreen.h | 24 + Minecraft.Client/Rect2i.cpp | 76 + Minecraft.Client/Rect2i.h | 24 + Minecraft.Client/RedDustParticle.cpp | 75 + Minecraft.Client/RedDustParticle.h | 17 + Minecraft.Client/RemotePlayer.cpp | 152 + Minecraft.Client/RemotePlayer.h | 33 + Minecraft.Client/RenameWorldScreen.cpp | 96 + Minecraft.Client/RenameWorldScreen.h | 25 + Minecraft.Client/Screen.cpp | 202 + Minecraft.Client/Screen.h | 54 + Minecraft.Client/ScreenSizeCalculator.cpp | 38 + Minecraft.Client/ScreenSizeCalculator.h | 15 + Minecraft.Client/ScrolledSelectionList.cpp | 358 + Minecraft.Client/ScrolledSelectionList.h | 62 + Minecraft.Client/SelectWorldScreen.cpp | 310 + Minecraft.Client/SelectWorldScreen.h | 74 + Minecraft.Client/ServerChunkCache.cpp | 968 + Minecraft.Client/ServerChunkCache.h | 101 + Minecraft.Client/ServerCommandDispatcher.cpp | 75 + Minecraft.Client/ServerCommandDispatcher.h | 11 + Minecraft.Client/ServerConnection.cpp | 204 + Minecraft.Client/ServerConnection.h | 49 + Minecraft.Client/ServerInterface.h | 29 + Minecraft.Client/ServerLevel.cpp | 1464 + Minecraft.Client/ServerLevel.h | 171 + Minecraft.Client/ServerLevelListener.cpp | 126 + Minecraft.Client/ServerLevelListener.h | 33 + Minecraft.Client/ServerPlayer.cpp | 1515 + Minecraft.Client/ServerPlayer.h | 164 + Minecraft.Client/ServerPlayerGameMode.cpp | 375 + Minecraft.Client/ServerPlayerGameMode.h | 60 + Minecraft.Client/Settings.cpp | 55 + Minecraft.Client/Settings.h | 21 + Minecraft.Client/SheepFurModel.cpp | 57 + Minecraft.Client/SheepFurModel.h | 13 + Minecraft.Client/SheepModel.cpp | 37 + Minecraft.Client/SheepModel.h | 13 + Minecraft.Client/SheepRenderer.cpp | 34 + Minecraft.Client/SheepRenderer.h | 14 + Minecraft.Client/SignModel.cpp | 22 + Minecraft.Client/SignModel.h | 16 + Minecraft.Client/SignRenderer.cpp | 120 + Minecraft.Client/SignRenderer.h | 12 + Minecraft.Client/SilverfishModel.cpp | 112 + Minecraft.Client/SilverfishModel.h | 26 + Minecraft.Client/SilverfishRenderer.cpp | 23 + Minecraft.Client/SilverfishRenderer.h | 23 + Minecraft.Client/SimpleIcon.cpp | 10 + Minecraft.Client/SimpleIcon.h | 11 + Minecraft.Client/SkeletonHeadModel.cpp | 43 + Minecraft.Client/SkeletonHeadModel.h | 19 + Minecraft.Client/SkeletonModel.cpp | 47 + Minecraft.Client/SkeletonModel.h | 13 + Minecraft.Client/SkinBox.h | 19 + Minecraft.Client/SkullTileRenderer.cpp | 112 + Minecraft.Client/SkullTileRenderer.h | 24 + Minecraft.Client/SlideButton.cpp | 51 + Minecraft.Client/SlideButton.h | 22 + Minecraft.Client/SlimeModel.cpp | 48 + Minecraft.Client/SlimeModel.h | 13 + Minecraft.Client/SlimeRenderer.cpp | 44 + Minecraft.Client/SlimeRenderer.h | 13 + Minecraft.Client/SmallButton.cpp | 22 + Minecraft.Client/SmallButton.h | 15 + Minecraft.Client/SmokeParticle.cpp | 80 + Minecraft.Client/SmokeParticle.h | 18 + Minecraft.Client/SnowManModel.cpp | 72 + Minecraft.Client/SnowManModel.h | 13 + Minecraft.Client/SnowManRenderer.cpp | 41 + Minecraft.Client/SnowManRenderer.h | 17 + Minecraft.Client/SnowShovelParticle.cpp | 66 + Minecraft.Client/SnowShovelParticle.h | 17 + Minecraft.Client/SpellParticle.cpp | 62 + Minecraft.Client/SpellParticle.h | 18 + Minecraft.Client/SpiderModel.cpp | 145 + Minecraft.Client/SpiderModel.h | 12 + Minecraft.Client/SpiderRenderer.cpp | 61 + Minecraft.Client/SpiderRenderer.h | 12 + Minecraft.Client/SplashParticle.cpp | 14 + Minecraft.Client/SplashParticle.h | 9 + Minecraft.Client/SquidModel.cpp | 55 + Minecraft.Client/SquidModel.h | 14 + Minecraft.Client/SquidRenderer.cpp | 35 + Minecraft.Client/SquidRenderer.h | 15 + Minecraft.Client/StatsCounter.cpp | 1344 + Minecraft.Client/StatsCounter.h | 103 + Minecraft.Client/StatsScreen.cpp | 670 + Minecraft.Client/StatsScreen.h | 133 + Minecraft.Client/StatsSyncher.cpp | 4 + Minecraft.Client/StatsSyncher.h | 47 + Minecraft.Client/StitchSlot.cpp | 156 + Minecraft.Client/StitchSlot.h | 28 + Minecraft.Client/StitchedTexture.cpp | 354 + Minecraft.Client/StitchedTexture.h | 89 + Minecraft.Client/Stitcher.cpp | 261 + Minecraft.Client/Stitcher.h | 60 + Minecraft.Client/StringTable.cpp | 172 + Minecraft.Client/StringTable.h | 78 + Minecraft.Client/SurvivalMode.cpp | 206 + Minecraft.Client/SurvivalMode.h | 32 + Minecraft.Client/SuspendedParticle.cpp | 42 + Minecraft.Client/SuspendedParticle.h | 11 + Minecraft.Client/SuspendedTownParticle.cpp | 37 + Minecraft.Client/SuspendedTownParticle.h | 11 + Minecraft.Client/TakeAnimationParticle.cpp | 80 + Minecraft.Client/TakeAnimationParticle.h | 22 + Minecraft.Client/TeleportCommand.cpp | 90 + Minecraft.Client/TeleportCommand.h | 12 + Minecraft.Client/TerrainParticle.cpp | 75 + Minecraft.Client/TerrainParticle.h | 18 + Minecraft.Client/Tesselator.cpp | 1080 + Minecraft.Client/Tesselator.h | 178 + Minecraft.Client/TexOffs.cpp | 9 + Minecraft.Client/TexOffs.h | 9 + Minecraft.Client/TextEditScreen.cpp | 119 + Minecraft.Client/TextEditScreen.h | 28 + Minecraft.Client/Texture.cpp | 899 + Minecraft.Client/Texture.h | 98 + Minecraft.Client/TextureHolder.cpp | 84 + Minecraft.Client/TextureHolder.h | 36 + Minecraft.Client/TextureManager.cpp | 196 + Minecraft.Client/TextureManager.h | 41 + Minecraft.Client/TextureMap.cpp | 248 + Minecraft.Client/TextureMap.h | 46 + Minecraft.Client/TexturePack.cpp | 70 + Minecraft.Client/TexturePack.h | 59 + Minecraft.Client/TexturePackRepository.cpp | 464 + Minecraft.Client/TexturePackRepository.h | 77 + Minecraft.Client/Textures.cpp | 1404 + Minecraft.Client/Textures.h | 287 + Minecraft.Client/TheEndPortalRenderer.cpp | 129 + Minecraft.Client/TheEndPortalRenderer.h | 16 + .../TileEntityRenderDispatcher.cpp | 164 + Minecraft.Client/TileEntityRenderDispatcher.h | 46 + Minecraft.Client/TileEntityRenderer.cpp | 30 + Minecraft.Client/TileEntityRenderer.h | 23 + Minecraft.Client/TileRenderer.cpp | 7694 ++++ Minecraft.Client/TileRenderer.h | 211 + Minecraft.Client/Timer.cpp | 138 + Minecraft.Client/Timer.h | 31 + Minecraft.Client/TitleScreen.cpp | 160 + Minecraft.Client/TitleScreen.h | 28 + Minecraft.Client/TntRenderer.cpp | 52 + Minecraft.Client/TntRenderer.h | 12 + Minecraft.Client/TrackedEntity.cpp | 929 + Minecraft.Client/TrackedEntity.h | 65 + Minecraft.Client/TrapScreen.cpp | 31 + Minecraft.Client/TrapScreen.h | 13 + Minecraft.Client/User.cpp | 45 + Minecraft.Client/User.h | 14 + Minecraft.Client/Vertex.cpp | 28 + Minecraft.Client/Vertex.h | 14 + Minecraft.Client/VideoSettingsScreen.cpp | 71 + Minecraft.Client/VideoSettingsScreen.h | 22 + Minecraft.Client/ViewportCuller.cpp | 159 + Minecraft.Client/ViewportCuller.h | 35 + Minecraft.Client/VillagerGolemModel.cpp | 90 + Minecraft.Client/VillagerGolemModel.h | 30 + Minecraft.Client/VillagerGolemRenderer.cpp | 69 + Minecraft.Client/VillagerGolemRenderer.h | 24 + Minecraft.Client/VillagerModel.cpp | 83 + Minecraft.Client/VillagerModel.h | 15 + Minecraft.Client/VillagerRenderer.cpp | 42 + Minecraft.Client/VillagerRenderer.h | 25 + Minecraft.Client/VillagerZombieModel.cpp | 62 + Minecraft.Client/VillagerZombieModel.h | 16 + Minecraft.Client/WaterDropParticle.cpp | 55 + Minecraft.Client/WaterDropParticle.h | 10 + .../Windows64/GameConfig/Minecraft.spa.h | 668 + .../WindowsLeaderboardManager.cpp | 5 + .../Leaderboards/WindowsLeaderboardManager.h | 36 + Minecraft.Client/Windows64/Minecraft_Macros.h | 41 + .../Windows64/Network/WinsockNetLayer.cpp | 844 + .../Windows64/Network/WinsockNetLayer.h | 147 + Minecraft.Client/Windows64/Resource.h | 31 + .../Windows64/Social/SocialManager.h | 137 + Minecraft.Client/Windows64/Windows64_App.cpp | 134 + Minecraft.Client/Windows64/Windows64_App.h | 34 + .../Windows64/Windows64_Minecraft.cpp | 1584 + .../Windows64/Windows64_UIController.cpp | 189 + .../Windows64/Windows64_UIController.h | 30 + Minecraft.Client/Windows64/XML/ATGXmlParser.h | 156 + Minecraft.Client/Windows64/Xbox_BuildVer.h | 53 + Minecraft.Client/WolfModel.cpp | 167 + Minecraft.Client/WolfModel.h | 21 + Minecraft.Client/WolfRenderer.cpp | 42 + Minecraft.Client/WolfRenderer.h | 11 + Minecraft.Client/WstringLookup.cpp | 54 + Minecraft.Client/WstringLookup.h | 20 + .../Xbox/GameConfig/ArcadeInfo.xml | Bin 0 -> 3826 bytes .../GameConfig/AvatarPackages/AvatarAwards | Bin 0 -> 503808 bytes .../Xbox/GameConfig/Minecraft.spa.h | 668 + .../Leaderboards/XboxLeaderboardManager.cpp | 520 + .../Leaderboards/XboxLeaderboardManager.h | 136 + Minecraft.Client/Xbox/Minecraftxex.xml | 14 + .../Xbox/Network/NetworkPlayerXbox.cpp | 121 + .../Xbox/Network/NetworkPlayerXbox.h | 39 + .../Network/PlatformNetworkManagerXbox.cpp | 1769 + .../Xbox/Network/PlatformNetworkManagerXbox.h | 184 + Minecraft.Client/Xbox/Network/extra.h | 4 + Minecraft.Client/Xbox/Resource.h | Bin 0 -> 2172 bytes .../Xbox/Social/SocialManager.cpp | 690 + Minecraft.Client/Xbox/Social/SocialManager.h | 135 + Minecraft.Client/Xbox/XML/ATGXmlParser.cpp | 963 + Minecraft.Client/Xbox/XML/ATGXmlParser.h | 156 + Minecraft.Client/Xbox/XML/xmlFilesCallback.h | 339 + Minecraft.Client/Xbox/Xbox_App.cpp | 3033 ++ Minecraft.Client/Xbox/Xbox_App.h | 197 + Minecraft.Client/Xbox/Xbox_BuildVer.h | 53 + Minecraft.Client/Xbox/Xbox_Minecraft.cpp | 1077 + Minecraft.Client/Xbox/Xbox_UIController.cpp | 341 + Minecraft.Client/Xbox/Xbox_UIController.h | 79 + Minecraft.Client/Xbox/targetver.h | 8 + Minecraft.Client/Xbox/xex-dev.xml | 7 + Minecraft.Client/Xbox/xex.xml | 11 + Minecraft.Client/ZombieModel.cpp | 36 + Minecraft.Client/ZombieModel.h | 16 + Minecraft.Client/ZombieRenderer.cpp | 91 + Minecraft.Client/ZombieRenderer.h | 41 + Minecraft.Client/extraX64client.h | 102 + Minecraft.Client/glWrapper.cpp | 389 + Minecraft.Client/stdafx.cpp | 8 + Minecraft.Client/stdafx.h | 352 + Minecraft.Client/stubs.cpp | 213 + Minecraft.Client/stubs.h | 298 + Minecraft.World/AABB.cpp | 342 + Minecraft.World/AABB.h | 65 + Minecraft.World/Abilities.cpp | 77 + Minecraft.World/Abilities.h | 32 + Minecraft.World/AbstractContainerMenu.cpp | 537 + Minecraft.World/AbstractContainerMenu.h | 88 + Minecraft.World/Achievement.cpp | 82 + Minecraft.World/Achievement.h | 38 + Minecraft.World/Achievements.cpp | 185 + Minecraft.World/Achievements.h | 92 + Minecraft.World/AddEntityPacket.cpp | 111 + Minecraft.World/AddEntityPacket.h | 58 + Minecraft.World/AddExperienceOrbPacket.cpp | 51 + Minecraft.World/AddExperienceOrbPacket.h | 24 + Minecraft.World/AddGlobalEntityPacket.cpp | 65 + Minecraft.World/AddGlobalEntityPacket.h | 25 + Minecraft.World/AddIslandLayer.cpp | 64 + Minecraft.World/AddIslandLayer.h | 11 + Minecraft.World/AddMobPacket.cpp | 140 + Minecraft.World/AddMobPacket.h | 37 + Minecraft.World/AddMushroomIslandLayer.cpp | 41 + Minecraft.World/AddMushroomIslandLayer.h | 9 + Minecraft.World/AddPaintingPacket.cpp | 58 + Minecraft.World/AddPaintingPacket.h | 27 + Minecraft.World/AddPlayerPacket.cpp | 142 + Minecraft.World/AddPlayerPacket.h | 43 + Minecraft.World/AddSnowLayer.cpp | 39 + Minecraft.World/AddSnowLayer.h | 9 + Minecraft.World/AdminLogCommand.h | 13 + Minecraft.World/AgableMob.cpp | 131 + Minecraft.World/AgableMob.h | 34 + Minecraft.World/AirTile.cpp | 6 + Minecraft.World/AirTile.h | 11 + Minecraft.World/Animal.cpp | 458 + Minecraft.World/Animal.h | 80 + Minecraft.World/AnimatePacket.cpp | 42 + Minecraft.World/AnimatePacket.h | 31 + Minecraft.World/AnvilTile.cpp | 117 + Minecraft.World/AnvilTile.h | 50 + Minecraft.World/AnvilTileItem.cpp | 18 + Minecraft.World/AnvilTileItem.h | 13 + Minecraft.World/ArmorDyeRecipe.cpp | 240 + Minecraft.World/ArmorDyeRecipe.h | 23 + Minecraft.World/ArmorItem.cpp | 229 + Minecraft.World/ArmorItem.h | 90 + Minecraft.World/ArmorRecipes.cpp | 158 + Minecraft.World/ArmorRecipes.h | 34 + Minecraft.World/ArmorSlot.cpp | 59 + Minecraft.World/ArmorSlot.h | 24 + Minecraft.World/ArrayWithLength.h | 115 + Minecraft.World/Arrays.h | 23 + Minecraft.World/Arrow.cpp | 531 + Minecraft.World/Arrow.h | 78 + Minecraft.World/ArrowAttackGoal.cpp | 91 + Minecraft.World/ArrowAttackGoal.h | 33 + Minecraft.World/ArrowDamageEnchantment.cpp | 22 + Minecraft.World/ArrowDamageEnchantment.h | 13 + Minecraft.World/ArrowFireEnchantment.cpp | 22 + Minecraft.World/ArrowFireEnchantment.h | 13 + Minecraft.World/ArrowInfiniteEnchantment.cpp | 22 + Minecraft.World/ArrowInfiniteEnchantment.h | 13 + Minecraft.World/ArrowKnockbackEnchantment.cpp | 22 + Minecraft.World/ArrowKnockbackEnchantment.h | 13 + Minecraft.World/AuxDataTileItem.cpp | 21 + Minecraft.World/AuxDataTileItem.h | 17 + Minecraft.World/AvoidPlayerGoal.cpp | 85 + Minecraft.World/AvoidPlayerGoal.h | 29 + Minecraft.World/AwardStatPacket.cpp | 89 + Minecraft.World/AwardStatPacket.h | 34 + Minecraft.World/BasicTree.cpp | 565 + Minecraft.World/BasicTree.h | 70 + Minecraft.World/BasicTypeContainers.cpp | 20 + Minecraft.World/BasicTypeContainers.h | 75 + Minecraft.World/BeachBiome.cpp | 18 + Minecraft.World/BeachBiome.h | 9 + Minecraft.World/BedItem.cpp | 59 + Minecraft.World/BedItem.h | 15 + Minecraft.World/BedTile.cpp | 332 + Minecraft.World/BedTile.h | 53 + Minecraft.World/BegGoal.cpp | 60 + Minecraft.World/BegGoal.h | 31 + Minecraft.World/BinaryHeap.cpp | 188 + Minecraft.World/BinaryHeap.h | 36 + Minecraft.World/Biome.cpp | 308 + Minecraft.World/Biome.h | 152 + Minecraft.World/BiomeCache.cpp | 165 + Minecraft.World/BiomeCache.h | 52 + Minecraft.World/BiomeDecorator.cpp | 328 + Minecraft.World/BiomeDecorator.h | 75 + Minecraft.World/BiomeInitLayer.cpp | 79 + Minecraft.World/BiomeInitLayer.h | 16 + Minecraft.World/BiomeOverrideLayer.cpp | 81 + Minecraft.World/BiomeOverrideLayer.h | 18 + Minecraft.World/BiomeSource.cpp | 638 + Minecraft.World/BiomeSource.h | 106 + Minecraft.World/BirchFeature.cpp | 81 + Minecraft.World/BirchFeature.h | 11 + Minecraft.World/Blaze.cpp | 227 + Minecraft.World/Blaze.h | 51 + Minecraft.World/BlockDestructionProgress.cpp | 57 + Minecraft.World/BlockDestructionProgress.h | 24 + Minecraft.World/BlockGenMethods.cpp | 224 + Minecraft.World/BlockGenMethods.h | 12 + Minecraft.World/BlockRegionUpdatePacket.cpp | 157 + Minecraft.World/BlockRegionUpdatePacket.h | 33 + Minecraft.World/BlockReplacements.cpp | 26 + Minecraft.World/BlockReplacements.h | 13 + Minecraft.World/Boat.cpp | 519 + Minecraft.World/Boat.h | 83 + Minecraft.World/BoatItem.cpp | 129 + Minecraft.World/BoatItem.h | 24 + Minecraft.World/BodyControl.cpp | 54 + Minecraft.World/BodyControl.h | 20 + Minecraft.World/BonusChestFeature.cpp | 88 + Minecraft.World/BonusChestFeature.h | 19 + Minecraft.World/BookItem.cpp | 17 + Minecraft.World/BookItem.h | 12 + Minecraft.World/BookshelfTile.cpp | 24 + Minecraft.World/BookshelfTile.h | 15 + Minecraft.World/BossMob.cpp | 36 + Minecraft.World/BossMob.h | 22 + Minecraft.World/BossMobPart.cpp | 43 + Minecraft.World/BossMobPart.h | 27 + Minecraft.World/BottleItem.cpp | 99 + Minecraft.World/BottleItem.h | 20 + Minecraft.World/BoundingBox.cpp | 166 + Minecraft.World/BoundingBox.h | 31 + Minecraft.World/BowItem.cpp | 109 + Minecraft.World/BowItem.h | 31 + Minecraft.World/BowlFoodItem.cpp | 16 + Minecraft.World/BowlFoodItem.h | 14 + Minecraft.World/BreakDoorGoal.cpp | 65 + Minecraft.World/BreakDoorGoal.h | 22 + Minecraft.World/BreedGoal.cpp | 116 + Minecraft.World/BreedGoal.h | 32 + Minecraft.World/BrewingStandMenu.cpp | 239 + Minecraft.World/BrewingStandMenu.h | 65 + Minecraft.World/BrewingStandTile.cpp | 136 + Minecraft.World/BrewingStandTile.h | 32 + Minecraft.World/BrewingStandTileEntity.cpp | 433 + Minecraft.World/BrewingStandTileEntity.h | 51 + Minecraft.World/BucketItem.cpp | 261 + Minecraft.World/BucketItem.h | 31 + Minecraft.World/Buffer.cpp | 73 + Minecraft.World/Buffer.h | 34 + Minecraft.World/BufferedOutputStream.cpp | 87 + Minecraft.World/BufferedOutputStream.h | 23 + Minecraft.World/BufferedReader.cpp | 173 + Minecraft.World/BufferedReader.h | 27 + Minecraft.World/Bush.cpp | 87 + Minecraft.World/Bush.h | 42 + Minecraft.World/ButtonTile.cpp | 366 + Minecraft.World/ButtonTile.h | 66 + Minecraft.World/ByteArrayInputStream.cpp | 118 + Minecraft.World/ByteArrayInputStream.h | 26 + Minecraft.World/ByteArrayOutputStream.cpp | 80 + Minecraft.World/ByteArrayOutputStream.h | 29 + Minecraft.World/ByteArrayTag.h | 53 + Minecraft.World/ByteBuffer.cpp | 478 + Minecraft.World/ByteBuffer.h | 57 + Minecraft.World/ByteTag.h | 36 + Minecraft.World/C4JThread.cpp | 1100 + Minecraft.World/C4JThread.h | 225 + Minecraft.World/CactusFeature.cpp | 27 + Minecraft.World/CactusFeature.h | 9 + Minecraft.World/CactusTile.cpp | 118 + Minecraft.World/CactusTile.h | 39 + Minecraft.World/CakeTile.cpp | 151 + Minecraft.World/CakeTile.h | 44 + Minecraft.World/CanyonFeature.cpp | 185 + Minecraft.World/CanyonFeature.h | 14 + Minecraft.World/CarrotOnAStickItem.cpp | 47 + Minecraft.World/CarrotOnAStickItem.h | 13 + Minecraft.World/CarrotTile.cpp | 42 + Minecraft.World/CarrotTile.h | 21 + Minecraft.World/CauldronTile.cpp | 177 + Minecraft.World/CauldronTile.h | 33 + Minecraft.World/CaveFeature.cpp | 92 + Minecraft.World/CaveFeature.h | 10 + Minecraft.World/CaveSpider.cpp | 64 + Minecraft.World/CaveSpider.h | 18 + Minecraft.World/ChatAutoCompletePacket.h | 56 + Minecraft.World/ChatPacket.cpp | 87 + Minecraft.World/ChatPacket.h | 98 + Minecraft.World/ChestTile.cpp | 316 + Minecraft.World/ChestTile.h | 38 + Minecraft.World/ChestTileEntity.cpp | 289 + Minecraft.World/ChestTileEntity.h | 63 + Minecraft.World/Chicken.cpp | 150 + Minecraft.World/Chicken.h | 42 + Minecraft.World/ChunkPos.cpp | 75 + Minecraft.World/ChunkPos.h | 40 + Minecraft.World/ChunkSource.h | 67 + Minecraft.World/ChunkStorage.h | 15 + .../ChunkStorageProfileDecorator.cpp | 71 + .../ChunkStorageProfileDecorator.h | 25 + Minecraft.World/ChunkTilesUpdatePacket.cpp | 173 + Minecraft.World/ChunkTilesUpdatePacket.h | 31 + Minecraft.World/ChunkVisibilityAreaPacket.cpp | 51 + Minecraft.World/ChunkVisibilityAreaPacket.h | 30 + Minecraft.World/ChunkVisibilityPacket.cpp | 47 + Minecraft.World/ChunkVisibilityPacket.h | 29 + Minecraft.World/Class.cpp | 5 + Minecraft.World/Class.h | 162 + Minecraft.World/ClayFeature.cpp | 38 + Minecraft.World/ClayFeature.h | 17 + Minecraft.World/ClayTile.cpp | 17 + Minecraft.World/ClayTile.h | 13 + Minecraft.World/ClientCommandPacket.cpp | 33 + Minecraft.World/ClientCommandPacket.h | 24 + Minecraft.World/ClientInformationPacket.h | 94 + Minecraft.World/ClientProtocolPacket.h | 74 + Minecraft.World/ClientSideMerchant.cpp | 64 + Minecraft.World/ClientSideMerchant.h | 30 + Minecraft.World/ClockItem.cpp | 41 + Minecraft.World/ClockItem.h | 19 + Minecraft.World/ClothDyeRecipes.cpp | 107 + Minecraft.World/ClothDyeRecipes.h | 8 + Minecraft.World/ClothTile.cpp | 38 + Minecraft.World/ClothTile.h | 22 + Minecraft.World/ClothTileItem.cpp | 68 + Minecraft.World/ClothTileItem.h | 17 + Minecraft.World/CoalItem.cpp | 22 + Minecraft.World/CoalItem.h | 17 + Minecraft.World/CocoaTile.cpp | 176 + Minecraft.World/CocoaTile.h | 38 + Minecraft.World/Color.cpp | 97 + Minecraft.World/Color.h | 15 + Minecraft.World/ColoredTileItem.cpp | 60 + Minecraft.World/ColoredTileItem.h | 25 + Minecraft.World/Command.cpp | 45 + Minecraft.World/Command.h | 28 + Minecraft.World/CommandDispatcher.cpp | 34 + Minecraft.World/CommandDispatcher.h | 19 + Minecraft.World/CommandSender.h | 12 + Minecraft.World/CommandsEnum.h | 15 + Minecraft.World/CommonStats.cpp | 298 + Minecraft.World/CommonStats.h | 80 + Minecraft.World/CompassItem.cpp | 42 + Minecraft.World/CompassItem.h | 19 + Minecraft.World/ComplexItem.cpp | 19 + Minecraft.World/ComplexItem.h | 18 + Minecraft.World/ComplexItemDataPacket.cpp | 57 + Minecraft.World/ComplexItemDataPacket.h | 27 + Minecraft.World/CompoundContainer.cpp | 75 + Minecraft.World/CompoundContainer.h | 36 + Minecraft.World/CompoundTag.h | 292 + Minecraft.World/CompressedTileStorage.cpp | 1361 + Minecraft.World/CompressedTileStorage.h | 111 + Minecraft.World/Connection.cpp | 675 + Minecraft.World/Connection.h | 145 + Minecraft.World/ConsoleSaveFile.h | 57 + Minecraft.World/ConsoleSaveFileConverter.cpp | 294 + Minecraft.World/ConsoleSaveFileConverter.h | 16 + Minecraft.World/ConsoleSaveFileIO.h | 7 + .../ConsoleSaveFileInputStream.cpp | 134 + Minecraft.World/ConsoleSaveFileInputStream.h | 26 + Minecraft.World/ConsoleSaveFileOriginal.cpp | 1059 + Minecraft.World/ConsoleSaveFileOriginal.h | 94 + .../ConsoleSaveFileOutputStream.cpp | 130 + Minecraft.World/ConsoleSaveFileOutputStream.h | 25 + Minecraft.World/ConsoleSaveFileSplit.cpp | 1711 + Minecraft.World/ConsoleSaveFileSplit.h | 143 + Minecraft.World/ConsoleSavePath.h | 15 + Minecraft.World/Container.cpp | 2 + Minecraft.World/Container.h | 23 + Minecraft.World/ContainerAckPacket.cpp | 45 + Minecraft.World/ContainerAckPacket.h | 30 + .../ContainerButtonClickPacket.cpp | 40 + Minecraft.World/ContainerButtonClickPacket.h | 22 + Minecraft.World/ContainerClickPacket.cpp | 65 + Minecraft.World/ContainerClickPacket.h | 30 + Minecraft.World/ContainerClosePacket.cpp | 37 + Minecraft.World/ContainerClosePacket.h | 24 + Minecraft.World/ContainerMenu.cpp | 120 + Minecraft.World/ContainerMenu.h | 22 + Minecraft.World/ContainerOpenPacket.cpp | 48 + Minecraft.World/ContainerOpenPacket.h | 37 + Minecraft.World/ContainerSetContentPacket.cpp | 60 + Minecraft.World/ContainerSetContentPacket.h | 26 + Minecraft.World/ContainerSetDataPacket.cpp | 45 + Minecraft.World/ContainerSetDataPacket.h | 24 + Minecraft.World/ContainerSetSlotPacket.cpp | 53 + Minecraft.World/ContainerSetSlotPacket.h | 30 + Minecraft.World/Control.h | 9 + Minecraft.World/ControlledByPlayerGoal.cpp | 152 + Minecraft.World/ControlledByPlayerGoal.h | 32 + Minecraft.World/Coord.h | 12 + Minecraft.World/CoralTile.cpp | 18 + Minecraft.World/CoralTile.h | 11 + Minecraft.World/Cow.cpp | 130 + Minecraft.World/Cow.h | 32 + Minecraft.World/CraftItemPacket.cpp | 46 + Minecraft.World/CraftItemPacket.h | 27 + Minecraft.World/CraftingContainer.cpp | 100 + Minecraft.World/CraftingContainer.h | 32 + Minecraft.World/CraftingMenu.cpp | 138 + Minecraft.World/CraftingMenu.h | 35 + Minecraft.World/Creature.cpp | 3 + Minecraft.World/Creature.h | 10 + Minecraft.World/Creeper.cpp | 169 + Minecraft.World/Creeper.h | 59 + Minecraft.World/CropTile.cpp | 169 + Minecraft.World/CropTile.h | 44 + Minecraft.World/CustomLevelSource.cpp | 640 + Minecraft.World/CustomLevelSource.h | 79 + Minecraft.World/CustomPayloadPacket.cpp | 75 + Minecraft.World/CustomPayloadPacket.h | 35 + Minecraft.World/DamageEnchantment.cpp | 62 + Minecraft.World/DamageEnchantment.h | 30 + Minecraft.World/DamageSource.cpp | 180 + Minecraft.World/DamageSource.h | 90 + Minecraft.World/DataInput.h | 22 + Minecraft.World/DataInputStream.cpp | 546 + Minecraft.World/DataInputStream.h | 35 + Minecraft.World/DataLayer.cpp | 62 + Minecraft.World/DataLayer.h | 22 + Minecraft.World/DataOutput.h | 20 + Minecraft.World/DataOutputStream.cpp | 268 + Minecraft.World/DataOutputStream.h | 37 + Minecraft.World/DeadBushFeature.cpp | 33 + Minecraft.World/DeadBushFeature.h | 15 + Minecraft.World/DeadBushTile.cpp | 46 + Minecraft.World/DeadBushTile.h | 16 + Minecraft.World/DebugOptionsPacket.cpp | 42 + Minecraft.World/DebugOptionsPacket.h | 26 + Minecraft.World/DecorationMaterial.h | 12 + Minecraft.World/DefaultGameModeCommand.cpp | 26 + Minecraft.World/DefaultGameModeCommand.h | 15 + Minecraft.World/DefendVillageTargetGoal.cpp | 24 + Minecraft.World/DefendVillageTargetGoal.h | 18 + Minecraft.World/Definitions.h | 40 + Minecraft.World/DelayedRelease.cpp | 46 + Minecraft.World/DelayedRelease.h | 30 + Minecraft.World/DerivedLevelData.cpp | 209 + Minecraft.World/DerivedLevelData.h | 60 + Minecraft.World/DescFormatter.h | 8 + Minecraft.World/DesertBiome.cpp | 33 + Minecraft.World/DesertBiome.h | 10 + Minecraft.World/DesertWellFeature.cpp | 90 + Minecraft.World/DesertWellFeature.h | 9 + Minecraft.World/DetectorRailTile.cpp | 115 + Minecraft.World/DetectorRailTile.h | 31 + Minecraft.World/Difficulty.h | 10 + Minecraft.World/DigDurabilityEnchantment.cpp | 36 + Minecraft.World/DigDurabilityEnchantment.h | 15 + Minecraft.World/DiggerItem.cpp | 64 + Minecraft.World/DiggerItem.h | 31 + Minecraft.World/DiggingEnchantment.cpp | 29 + Minecraft.World/DiggingEnchantment.h | 14 + Minecraft.World/Dimension.cpp | 243 + Minecraft.World/Dimension.h | 62 + Minecraft.World/DiodeTile.cpp | 299 + Minecraft.World/DiodeTile.h | 50 + Minecraft.World/Direction.cpp | 62 + Minecraft.World/Direction.h | 32 + Minecraft.World/DirectionalTile.cpp | 16 + Minecraft.World/DirectionalTile.h | 17 + Minecraft.World/DirectoryLevelStorage.cpp | 824 + Minecraft.World/DirectoryLevelStorage.h | 144 + .../DirectoryLevelStorageSource.cpp | 139 + Minecraft.World/DirectoryLevelStorageSource.h | 34 + Minecraft.World/DirtTile.cpp | 6 + Minecraft.World/DirtTile.h | 9 + Minecraft.World/DisconnectPacket.cpp | 48 + Minecraft.World/DisconnectPacket.h | 73 + Minecraft.World/DispenserTile.cpp | 573 + Minecraft.World/DispenserTile.h | 58 + Minecraft.World/DispenserTileEntity.cpp | 224 + Minecraft.World/DispenserTileEntity.h | 52 + Minecraft.World/Distort.cpp | 13 + Minecraft.World/Distort.h | 14 + Minecraft.World/DoorInfo.cpp | 69 + Minecraft.World/DoorInfo.h | 29 + Minecraft.World/DoorInteractGoal.cpp | 73 + Minecraft.World/DoorInteractGoal.h | 29 + Minecraft.World/DoorItem.cpp | 75 + Minecraft.World/DoorItem.h | 20 + Minecraft.World/DoorTile.cpp | 341 + Minecraft.World/DoorTile.h | 60 + Minecraft.World/DoubleTag.h | 37 + Minecraft.World/DownfallLayer.cpp | 21 + Minecraft.World/DownfallLayer.h | 10 + Minecraft.World/DownfallMixerLayer.cpp | 24 + Minecraft.World/DownfallMixerLayer.h | 14 + Minecraft.World/DragonFireball.cpp | 86 + Minecraft.World/DragonFireball.h | 37 + Minecraft.World/DungeonFeature.cpp | 191 + Minecraft.World/DungeonFeature.h | 12 + Minecraft.World/DurangoStats.cpp | 1221 + Minecraft.World/DurangoStats.h | 311 + Minecraft.World/DyePowderItem.cpp | 317 + Minecraft.World/DyePowderItem.h | 50 + Minecraft.World/EatTileGoal.cpp | 73 + Minecraft.World/EatTileGoal.h | 28 + Minecraft.World/EggItem.cpp | 31 + Minecraft.World/EggItem.h | 15 + Minecraft.World/EggTile.cpp | 173 + Minecraft.World/EggTile.h | 29 + Minecraft.World/Emboss.cpp | 12 + Minecraft.World/Emboss.h | 13 + Minecraft.World/EmptyLevelChunk.cpp | 222 + Minecraft.World/EmptyLevelChunk.h | 54 + Minecraft.World/EnchantItemCommand.cpp | 85 + Minecraft.World/EnchantItemCommand.h | 15 + Minecraft.World/EnchantedBookItem.cpp | 144 + Minecraft.World/EnchantedBookItem.h | 25 + Minecraft.World/Enchantment.cpp | 202 + Minecraft.World/Enchantment.h | 87 + Minecraft.World/EnchantmentCategory.cpp | 42 + Minecraft.World/EnchantmentCategory.h | 19 + Minecraft.World/EnchantmentContainer.cpp | 18 + Minecraft.World/EnchantmentContainer.h | 18 + Minecraft.World/EnchantmentHelper.cpp | 477 + Minecraft.World/EnchantmentHelper.h | 110 + Minecraft.World/EnchantmentInstance.cpp | 17 + Minecraft.World/EnchantmentInstance.h | 16 + Minecraft.World/EnchantmentMenu.cpp | 299 + Minecraft.World/EnchantmentMenu.h | 41 + Minecraft.World/EnchantmentSlot.h | 16 + Minecraft.World/EnchantmentTableEntity.cpp | 109 + Minecraft.World/EnchantmentTableEntity.h | 25 + Minecraft.World/EnchantmentTableTile.cpp | 92 + Minecraft.World/EnchantmentTableTile.h | 29 + Minecraft.World/EndPodiumFeature.cpp | 86 + Minecraft.World/EndPodiumFeature.h | 14 + Minecraft.World/EndTag.h | 25 + Minecraft.World/EnderChestTile.cpp | 117 + Minecraft.World/EnderChestTile.h | 29 + Minecraft.World/EnderChestTileEntity.cpp | 99 + Minecraft.World/EnderChestTileEntity.h | 30 + Minecraft.World/EnderCrystal.cpp | 128 + Minecraft.World/EnderCrystal.h | 42 + Minecraft.World/EnderDragon.cpp | 1941 + Minecraft.World/EnderDragon.h | 177 + Minecraft.World/EnderEyeItem.cpp | 238 + Minecraft.World/EnderEyeItem.h | 13 + Minecraft.World/EnderMan.cpp | 411 + Minecraft.World/EnderMan.h | 64 + Minecraft.World/EnderpearlItem.cpp | 34 + Minecraft.World/EnderpearlItem.h | 13 + Minecraft.World/Enemy.cpp | 10 + Minecraft.World/Enemy.h | 14 + Minecraft.World/Entity.cpp | 1956 + Minecraft.World/Entity.h | 397 + .../EntityActionAtPositionPacket.cpp | 56 + .../EntityActionAtPositionPacket.h | 23 + Minecraft.World/EntityDamageSource.cpp | 38 + Minecraft.World/EntityDamageSource.h | 26 + Minecraft.World/EntityEvent.h | 29 + Minecraft.World/EntityEventPacket.cpp | 41 + Minecraft.World/EntityEventPacket.h | 25 + Minecraft.World/EntityIO.cpp | 264 + Minecraft.World/EntityIO.h | 61 + Minecraft.World/EntityPos.cpp | 62 + Minecraft.World/EntityPos.h | 15 + Minecraft.World/EntityTile.cpp | 32 + Minecraft.World/EntityTile.h | 15 + Minecraft.World/Exceptions.h | 29 + Minecraft.World/ExperienceCommand.cpp | 41 + Minecraft.World/ExperienceCommand.h | 15 + Minecraft.World/ExperienceItem.cpp | 32 + Minecraft.World/ExperienceItem.h | 15 + Minecraft.World/ExperienceOrb.cpp | 330 + Minecraft.World/ExperienceOrb.h | 60 + Minecraft.World/ExplodePacket.cpp | 136 + Minecraft.World/ExplodePacket.h | 37 + Minecraft.World/Explosion.cpp | 265 + Minecraft.World/Explosion.h | 42 + Minecraft.World/ExtremeHillsBiome.cpp | 30 + Minecraft.World/ExtremeHillsBiome.h | 16 + Minecraft.World/EyeOfEnderSignal.cpp | 206 + Minecraft.World/EyeOfEnderSignal.h | 41 + Minecraft.World/Facing.cpp | 22 + Minecraft.World/Facing.h | 17 + Minecraft.World/FallingTile.cpp | 240 + Minecraft.World/FallingTile.h | 49 + Minecraft.World/FarmTile.cpp | 147 + Minecraft.World/FarmTile.h | 36 + Minecraft.World/FastNoise.cpp | 114 + Minecraft.World/FastNoise.h | 17 + Minecraft.World/Feature.cpp | 31 + Minecraft.World/Feature.h | 20 + Minecraft.World/FenceGateTile.cpp | 147 + Minecraft.World/FenceGateTile.h | 26 + Minecraft.World/FenceTile.cpp | 132 + Minecraft.World/FenceTile.h | 23 + Minecraft.World/File.cpp | 702 + Minecraft.World/File.h | 56 + Minecraft.World/FileFilter.h | 10 + Minecraft.World/FileHeader.cpp | 681 + Minecraft.World/FileHeader.h | 203 + Minecraft.World/FileInputStream.cpp | 204 + Minecraft.World/FileInputStream.h | 20 + Minecraft.World/FileOutputStream.cpp | 153 + Minecraft.World/FileOutputStream.h | 19 + Minecraft.World/FilenameFilter.h | 13 + Minecraft.World/FireAspectEnchantment.cpp | 22 + Minecraft.World/FireAspectEnchantment.h | 13 + Minecraft.World/FireChargeItem.cpp | 67 + Minecraft.World/FireChargeItem.h | 20 + Minecraft.World/FireTile.cpp | 407 + Minecraft.World/FireTile.h | 63 + Minecraft.World/Fireball.cpp | 415 + Minecraft.World/Fireball.h | 73 + Minecraft.World/FishingHook.cpp | 450 + Minecraft.World/FishingHook.h | 63 + Minecraft.World/FishingRodItem.cpp | 67 + Minecraft.World/FishingRodItem.h | 27 + Minecraft.World/FixedBiomeSource.cpp | 153 + Minecraft.World/FixedBiomeSource.h | 37 + Minecraft.World/FlatLayer.cpp | 20 + Minecraft.World/FlatLayer.h | 13 + Minecraft.World/FlatLevelSource.cpp | 153 + Minecraft.World/FlatLevelSource.h | 44 + Minecraft.World/FleeSunGoal.cpp | 52 + Minecraft.World/FleeSunGoal.h | 26 + Minecraft.World/FlintAndSteelItem.cpp | 72 + Minecraft.World/FlintAndSteelItem.h | 14 + Minecraft.World/FlippedIcon.cpp | 88 + Minecraft.World/FlippedIcon.h | 31 + Minecraft.World/FloatBuffer.cpp | 66 + Minecraft.World/FloatBuffer.h | 18 + Minecraft.World/FloatGoal.cpp | 22 + Minecraft.World/FloatGoal.h | 17 + Minecraft.World/FloatTag.h | 37 + Minecraft.World/FlowerFeature.cpp | 40 + Minecraft.World/FlowerFeature.h | 14 + Minecraft.World/FlowerPotTile.cpp | 192 + Minecraft.World/FlowerPotTile.h | 37 + Minecraft.World/FlyingMob.cpp | 81 + Minecraft.World/FlyingMob.h | 18 + Minecraft.World/FoliageColor.cpp | 40 + Minecraft.World/FoliageColor.h | 17 + Minecraft.World/FollowOwnerGoal.cpp | 85 + Minecraft.World/FollowOwnerGoal.h | 34 + Minecraft.World/FollowParentGoal.cpp | 65 + Minecraft.World/FollowParentGoal.h | 23 + Minecraft.World/FoodConstants.cpp | 35 + Minecraft.World/FoodConstants.h | 37 + Minecraft.World/FoodData.cpp | 159 + Minecraft.World/FoodData.h | 34 + Minecraft.World/FoodItem.cpp | 120 + Minecraft.World/FoodItem.h | 49 + Minecraft.World/FoodRecipies.cpp | 122 + Minecraft.World/FoodRecipies.h | 7 + Minecraft.World/ForestBiome.cpp | 26 + Minecraft.World/ForestBiome.h | 10 + Minecraft.World/FurnaceMenu.cpp | 178 + Minecraft.World/FurnaceMenu.h | 38 + Minecraft.World/FurnaceRecipes.cpp | 82 + Minecraft.World/FurnaceRecipes.h | 30 + Minecraft.World/FurnaceResultSlot.cpp | 94 + Minecraft.World/FurnaceResultSlot.h | 23 + Minecraft.World/FurnaceTile.cpp | 208 + Minecraft.World/FurnaceTile.h | 39 + Minecraft.World/FurnaceTileEntity.cpp | 350 + Minecraft.World/FurnaceTileEntity.h | 78 + Minecraft.World/FuzzyZoomLayer.cpp | 72 + Minecraft.World/FuzzyZoomLayer.h | 17 + Minecraft.World/GZIPInputStream.h | 17 + Minecraft.World/GZIPOutputStream.h | 17 + Minecraft.World/GameCommandPacket.cpp | 72 + Minecraft.World/GameCommandPacket.h | 26 + Minecraft.World/GameEventPacket.cpp | 59 + Minecraft.World/GameEventPacket.h | 45 + Minecraft.World/GameModeCommand.cpp | 53 + Minecraft.World/GameModeCommand.h | 16 + Minecraft.World/GasMaterial.h | 12 + Minecraft.World/GeneralStat.cpp | 18 + Minecraft.World/GeneralStat.h | 12 + Minecraft.World/GenericStats.cpp | 1284 + Minecraft.World/GenericStats.h | 348 + Minecraft.World/GetInfoPacket.cpp | 22 + Minecraft.World/GetInfoPacket.h | 16 + Minecraft.World/Ghast.cpp | 249 + Minecraft.World/Ghast.h | 65 + Minecraft.World/Giant.cpp | 32 + Minecraft.World/Giant.h | 18 + Minecraft.World/GiveItemCommand.cpp | 50 + Minecraft.World/GiveItemCommand.h | 15 + Minecraft.World/GlassTile.cpp | 31 + Minecraft.World/GlassTile.h | 17 + Minecraft.World/GlobalEntity.cpp | 3 + Minecraft.World/GlobalEntity.h | 11 + Minecraft.World/Goal.cpp | 39 + Minecraft.World/Goal.h | 23 + Minecraft.World/GoalSelector.cpp | 147 + Minecraft.World/GoalSelector.h | 45 + Minecraft.World/GoldenAppleItem.cpp | 53 + Minecraft.World/GoldenAppleItem.h | 21 + Minecraft.World/Golem.cpp | 39 + Minecraft.World/Golem.h | 25 + Minecraft.World/GrassColor.cpp | 21 + Minecraft.World/GrassColor.h | 12 + Minecraft.World/GrassTile.cpp | 146 + Minecraft.World/GrassTile.h | 33 + Minecraft.World/GravelTile.cpp | 13 + Minecraft.World/GravelTile.h | 11 + Minecraft.World/GroundBushFeature.cpp | 43 + Minecraft.World/GroundBushFeature.h | 15 + Minecraft.World/GrowMushroomIslandLayer.cpp | 42 + Minecraft.World/GrowMushroomIslandLayer.h | 9 + Minecraft.World/HalfSlabTile.cpp | 143 + Minecraft.World/HalfSlabTile.h | 33 + Minecraft.World/HalfTransparentTile.cpp | 32 + Minecraft.World/HalfTransparentTile.h | 19 + Minecraft.World/HangingEntity.cpp | 292 + Minecraft.World/HangingEntity.h | 42 + Minecraft.World/HangingEntityItem.cpp | 88 + Minecraft.World/HangingEntityItem.h | 21 + Minecraft.World/HashExtension.h | 20 + Minecraft.World/Hasher.cpp | 28 + Minecraft.World/Hasher.h | 12 + Minecraft.World/HatchetItem.cpp | 33 + Minecraft.World/HatchetItem.h | 15 + Minecraft.World/HeavyTile.cpp | 91 + Minecraft.World/HeavyTile.h | 26 + Minecraft.World/HellBiome.cpp | 16 + Minecraft.World/HellBiome.h | 8 + Minecraft.World/HellDimension.cpp | 89 + Minecraft.World/HellDimension.h | 23 + Minecraft.World/HellFireFeature.cpp | 19 + Minecraft.World/HellFireFeature.h | 10 + Minecraft.World/HellFlatLevelSource.cpp | 224 + Minecraft.World/HellFlatLevelSource.h | 51 + Minecraft.World/HellPortalFeature.cpp | 37 + Minecraft.World/HellPortalFeature.h | 8 + Minecraft.World/HellRandomLevelSource.cpp | 544 + Minecraft.World/HellRandomLevelSource.h | 72 + Minecraft.World/HellSandTile.cpp | 21 + Minecraft.World/HellSandTile.h | 11 + Minecraft.World/HellSpringFeature.cpp | 42 + Minecraft.World/HellSpringFeature.h | 14 + Minecraft.World/HellStoneTile.cpp | 6 + Minecraft.World/HellStoneTile.h | 8 + Minecraft.World/HitResult.cpp | 33 + Minecraft.World/HitResult.h | 22 + Minecraft.World/HoeItem.cpp | 51 + Minecraft.World/HoeItem.h | 19 + Minecraft.World/HouseFeature.cpp | 193 + Minecraft.World/HouseFeature.h | 9 + Minecraft.World/HugeMushroomFeature.cpp | 111 + Minecraft.World/HugeMushroomFeature.h | 13 + Minecraft.World/HugeMushroomTile.cpp | 71 + Minecraft.World/HugeMushroomTile.h | 26 + Minecraft.World/HurtByTargetGoal.cpp | 45 + Minecraft.World/HurtByTargetGoal.h | 17 + Minecraft.World/I18n.cpp | 20 + Minecraft.World/I18n.h | 15 + Minecraft.World/IceBiome.cpp | 6 + Minecraft.World/IceBiome.h | 8 + Minecraft.World/IceTile.cpp | 83 + Minecraft.World/IceTile.h | 19 + Minecraft.World/Icon.h | 34 + Minecraft.World/IconRegister.h | 12 + Minecraft.World/ImprovedNoise.cpp | 216 + Minecraft.World/ImprovedNoise.h | 29 + .../IndirectEntityDamageSource.cpp | 48 + Minecraft.World/IndirectEntityDamageSource.h | 25 + Minecraft.World/InputOutputStream.h | 20 + Minecraft.World/InputStream.cpp | 9 + Minecraft.World/InputStream.h | 17 + Minecraft.World/InputStreamReader.cpp | 52 + Minecraft.World/InputStreamReader.h | 18 + Minecraft.World/InstantenousMobEffect.cpp | 16 + Minecraft.World/InstantenousMobEffect.h | 11 + Minecraft.World/IntArrayTag.h | 66 + Minecraft.World/IntBuffer.cpp | 113 + Minecraft.World/IntBuffer.h | 21 + Minecraft.World/IntCache.cpp | 164 + Minecraft.World/IntCache.h | 34 + Minecraft.World/IntTag.h | 36 + Minecraft.World/InteractGoal.cpp | 13 + Minecraft.World/InteractGoal.h | 10 + Minecraft.World/InteractPacket.cpp | 48 + Minecraft.World/InteractPacket.h | 25 + Minecraft.World/Inventory.cpp | 746 + Minecraft.World/Inventory.h | 136 + Minecraft.World/InventoryMenu.cpp | 247 + Minecraft.World/InventoryMenu.h | 44 + Minecraft.World/IslandLayer.cpp | 25 + Minecraft.World/IslandLayer.h | 11 + Minecraft.World/Item.cpp | 1110 + Minecraft.World/Item.h | 718 + Minecraft.World/ItemEntity.cpp | 306 + Minecraft.World/ItemEntity.h | 74 + Minecraft.World/ItemFrame.cpp | 145 + Minecraft.World/ItemFrame.h | 41 + Minecraft.World/ItemInstance.cpp | 727 + Minecraft.World/ItemInstance.h | 154 + Minecraft.World/ItemStat.cpp | 11 + Minecraft.World/ItemStat.h | 14 + Minecraft.World/JavaIntHash.h | 77 + Minecraft.World/JavaMath.cpp | 76 + Minecraft.World/JavaMath.h | 19 + Minecraft.World/JumpControl.cpp | 21 + Minecraft.World/JumpControl.h | 18 + Minecraft.World/JungleBiome.cpp | 63 + Minecraft.World/JungleBiome.h | 14 + Minecraft.World/KeepAlivePacket.cpp | 52 + Minecraft.World/KeepAlivePacket.h | 25 + Minecraft.World/KickPlayerPacket.cpp | 37 + Minecraft.World/KickPlayerPacket.h | 22 + Minecraft.World/KillCommand.cpp | 19 + Minecraft.World/KillCommand.h | 10 + Minecraft.World/KnockbackEnchantment.cpp | 22 + Minecraft.World/KnockbackEnchantment.h | 13 + Minecraft.World/LadderTile.cpp | 112 + Minecraft.World/LadderTile.h | 26 + Minecraft.World/LakeFeature.cpp | 175 + Minecraft.World/LakeFeature.h | 14 + Minecraft.World/Language.cpp | 48 + Minecraft.World/Language.h | 14 + Minecraft.World/LargeCaveFeature.cpp | 196 + Minecraft.World/LargeCaveFeature.h | 11 + Minecraft.World/LargeFeature.cpp | 37 + Minecraft.World/LargeFeature.h | 23 + Minecraft.World/LargeHellCaveFeature.cpp | 184 + Minecraft.World/LargeHellCaveFeature.h | 11 + Minecraft.World/LavaSlime.cpp | 144 + Minecraft.World/LavaSlime.h | 46 + Minecraft.World/Layer.cpp | 199 + Minecraft.World/Layer.h | 36 + Minecraft.World/LeafTile.cpp | 337 + Minecraft.World/LeafTile.h | 76 + Minecraft.World/LeafTileItem.cpp | 47 + Minecraft.World/LeafTileItem.h | 17 + Minecraft.World/LeapAtTargetGoal.cpp | 40 + Minecraft.World/LeapAtTargetGoal.h | 18 + Minecraft.World/Level.cpp | 4754 ++ Minecraft.World/Level.h | 537 + Minecraft.World/LevelChunk.cpp | 2463 ++ Minecraft.World/LevelChunk.h | 260 + Minecraft.World/LevelConflictException.cpp | 6 + Minecraft.World/LevelConflictException.h | 13 + Minecraft.World/LevelData.cpp | 589 + Minecraft.World/LevelData.h | 133 + Minecraft.World/LevelEvent.h | 41 + Minecraft.World/LevelEventPacket.cpp | 54 + Minecraft.World/LevelEventPacket.h | 24 + Minecraft.World/LevelListener.h | 40 + Minecraft.World/LevelObjectInputStream.h | 34 + Minecraft.World/LevelSettings.cpp | 185 + Minecraft.World/LevelSettings.h | 67 + Minecraft.World/LevelSoundPacket.cpp | 96 + Minecraft.World/LevelSoundPacket.h | 38 + Minecraft.World/LevelSource.h | 29 + Minecraft.World/LevelStorage.cpp | 6 + Minecraft.World/LevelStorage.h | 37 + .../LevelStorageProfilerDecorator.cpp | 57 + .../LevelStorageProfilerDecorator.h | 27 + Minecraft.World/LevelStorageSource.h | 37 + Minecraft.World/LevelSummary.cpp | 69 + Minecraft.World/LevelSummary.h | 28 + Minecraft.World/LevelType.cpp | 118 + Minecraft.World/LevelType.h | 39 + Minecraft.World/LeverTile.cpp | 309 + Minecraft.World/LeverTile.h | 31 + Minecraft.World/LightGemFeature.cpp | 37 + Minecraft.World/LightGemFeature.h | 8 + Minecraft.World/LightGemTile.cpp | 22 + Minecraft.World/LightGemTile.h | 13 + Minecraft.World/LightLayer.h | 14 + Minecraft.World/LightningBolt.cpp | 143 + Minecraft.World/LightningBolt.h | 36 + Minecraft.World/LiquidMaterial.h | 12 + Minecraft.World/LiquidTile.cpp | 418 + Minecraft.World/LiquidTile.h | 62 + Minecraft.World/LiquidTileDynamic.cpp | 342 + Minecraft.World/LiquidTileDynamic.h | 54 + Minecraft.World/LiquidTileStatic.cpp | 85 + Minecraft.World/LiquidTileStatic.h | 20 + Minecraft.World/ListTag.h | 144 + Minecraft.World/LockedChestTile.cpp | 22 + Minecraft.World/LockedChestTile.h | 14 + Minecraft.World/LoginPacket.cpp | 183 + Minecraft.World/LoginPacket.h | 45 + Minecraft.World/LongTag.h | 36 + Minecraft.World/LookAtPlayerGoal.cpp | 57 + Minecraft.World/LookAtPlayerGoal.h | 32 + Minecraft.World/LookAtTradingPlayerGoal.cpp | 19 + Minecraft.World/LookAtTradingPlayerGoal.h | 16 + Minecraft.World/LookControl.cpp | 117 + Minecraft.World/LookControl.h | 33 + Minecraft.World/LootBonusEnchantment.cpp | 31 + Minecraft.World/LootBonusEnchantment.h | 14 + Minecraft.World/MakeLoveGoal.cpp | 103 + Minecraft.World/MakeLoveGoal.h | 33 + Minecraft.World/MapItem.cpp | 347 + Minecraft.World/MapItem.h | 23 + Minecraft.World/MapItemSavedData.cpp | 573 + Minecraft.World/MapItemSavedData.h | 89 + Minecraft.World/Material.cpp | 192 + Minecraft.World/Material.h | 92 + Minecraft.World/MaterialColor.cpp | 46 + Minecraft.World/MaterialColor.h | 31 + Minecraft.World/McRegionChunkStorage.cpp | 460 + Minecraft.World/McRegionChunkStorage.h | 43 + Minecraft.World/McRegionLevelStorage.cpp | 103 + Minecraft.World/McRegionLevelStorage.h | 22 + .../McRegionLevelStorageSource.cpp | 365 + Minecraft.World/McRegionLevelStorageSource.h | 68 + Minecraft.World/MegaTreeFeature.cpp | 201 + Minecraft.World/MegaTreeFeature.h | 19 + Minecraft.World/MeleeAttackGoal.cpp | 96 + Minecraft.World/MeleeAttackGoal.h | 38 + Minecraft.World/MelonTile.cpp | 45 + Minecraft.World/MelonTile.h | 24 + Minecraft.World/MemoryChunkStorage.cpp | 25 + Minecraft.World/MemoryChunkStorage.h | 14 + Minecraft.World/MemoryLevelStorage.cpp | 63 + Minecraft.World/MemoryLevelStorage.h | 31 + Minecraft.World/MemoryLevelStorageSource.cpp | 61 + Minecraft.World/MemoryLevelStorageSource.h | 21 + Minecraft.World/MenuBackup.cpp | 47 + Minecraft.World/MenuBackup.h | 21 + Minecraft.World/Merchant.h | 17 + Minecraft.World/MerchantContainer.cpp | 183 + Minecraft.World/MerchantContainer.h | 42 + Minecraft.World/MerchantMenu.cpp | 150 + Minecraft.World/MerchantMenu.h | 46 + Minecraft.World/MerchantRecipe.cpp | 146 + Minecraft.World/MerchantRecipe.h | 35 + Minecraft.World/MerchantRecipeList.cpp | 195 + Minecraft.World/MerchantRecipeList.h | 35 + Minecraft.World/MerchantResultSlot.cpp | 94 + Minecraft.World/MerchantResultSlot.h | 33 + Minecraft.World/MetalTile.cpp | 6 + Minecraft.World/MetalTile.h | 8 + Minecraft.World/MilkBucketItem.cpp | 41 + Minecraft.World/MilkBucketItem.h | 17 + Minecraft.World/MineShaftFeature.cpp | 23 + Minecraft.World/MineShaftFeature.h | 10 + Minecraft.World/MineShaftPieces.cpp | 697 + Minecraft.World/MineShaftPieces.h | 96 + Minecraft.World/MineShaftStart.cpp | 12 + Minecraft.World/MineShaftStart.h | 9 + Minecraft.World/Minecart.cpp | 1211 + Minecraft.World/Minecart.h | 114 + Minecraft.World/MinecartItem.cpp | 33 + Minecraft.World/MinecartItem.h | 14 + Minecraft.World/Minecraft.World.cpp | 104 + Minecraft.World/Minecraft.World.h | 3 + Minecraft.World/Minecraft.World.vcxproj | 3966 ++ .../Minecraft.World.vcxproj.filters | 4927 +++ Minecraft.World/Mob.cpp | 1943 + Minecraft.World/Mob.h | 369 + Minecraft.World/MobCategory.cpp | 71 + Minecraft.World/MobCategory.h | 82 + Minecraft.World/MobEffect.cpp | 270 + Minecraft.World/MobEffect.h | 114 + Minecraft.World/MobEffectInstance.cpp | 139 + Minecraft.World/MobEffectInstance.h | 42 + Minecraft.World/MobSpawner.cpp | 651 + Minecraft.World/MobSpawner.h | 46 + Minecraft.World/MobSpawnerTile.cpp | 49 + Minecraft.World/MobSpawnerTile.h | 19 + Minecraft.World/MobSpawnerTileEntity.cpp | 233 + Minecraft.World/MobSpawnerTileEntity.h | 59 + Minecraft.World/MobType.h | 9 + Minecraft.World/MockedLevelStorage.cpp | 49 + Minecraft.World/MockedLevelStorage.h | 22 + Minecraft.World/Monster.cpp | 159 + Minecraft.World/Monster.h | 48 + Minecraft.World/MonsterPlacerItem.cpp | 291 + Minecraft.World/MonsterPlacerItem.h | 42 + Minecraft.World/MonsterRoomFeature.cpp | 140 + Minecraft.World/MonsterRoomFeature.h | 16 + Minecraft.World/MouseInventoryClickHandler.h | 84 + Minecraft.World/MoveControl.cpp | 75 + Minecraft.World/MoveControl.h | 34 + Minecraft.World/MoveEntityPacket.cpp | 168 + Minecraft.World/MoveEntityPacket.h | 78 + Minecraft.World/MoveEntityPacketSmall.cpp | 191 + Minecraft.World/MoveEntityPacketSmall.h | 79 + Minecraft.World/MoveIndoorsGoal.cpp | 65 + Minecraft.World/MoveIndoorsGoal.h | 22 + Minecraft.World/MovePlayerPacket.cpp | 188 + Minecraft.World/MovePlayerPacket.h | 78 + Minecraft.World/MoveThroughVillageGoal.cpp | 127 + Minecraft.World/MoveThroughVillageGoal.h | 32 + .../MoveTowardsRestrictionGoal.cpp | 38 + Minecraft.World/MoveTowardsRestrictionGoal.h | 18 + Minecraft.World/MoveTowardsTargetGoal.cpp | 43 + Minecraft.World/MoveTowardsTargetGoal.h | 20 + Minecraft.World/Mth.cpp | 172 + Minecraft.World/Mth.h | 42 + Minecraft.World/MultiTextureTileItem.cpp | 46 + Minecraft.World/MultiTextureTileItem.h | 22 + Minecraft.World/Mushroom.cpp | 107 + Minecraft.World/Mushroom.h | 23 + Minecraft.World/MushroomCow.cpp | 84 + Minecraft.World/MushroomCow.h | 17 + Minecraft.World/MushroomIslandBiome.cpp | 25 + Minecraft.World/MushroomIslandBiome.h | 8 + Minecraft.World/MusicTile.cpp | 84 + Minecraft.World/MusicTile.h | 16 + Minecraft.World/MusicTileEntity.cpp | 64 + Minecraft.World/MusicTileEntity.h | 26 + Minecraft.World/MycelTile.cpp | 74 + Minecraft.World/MycelTile.h | 23 + Minecraft.World/NbtIo.cpp | 65 + Minecraft.World/NbtIo.h | 17 + Minecraft.World/NbtSlotFile.cpp | 250 + Minecraft.World/NbtSlotFile.h | 44 + .../NearestAttackableTargetGoal.cpp | 71 + Minecraft.World/NearestAttackableTargetGoal.h | 36 + Minecraft.World/NetherBridgeFeature.cpp | 119 + Minecraft.World/NetherBridgeFeature.h | 30 + Minecraft.World/NetherBridgePieces.cpp | 1453 + Minecraft.World/NetherBridgePieces.h | 343 + Minecraft.World/NetherSphere.cpp | 26 + Minecraft.World/NetherSphere.h | 16 + Minecraft.World/NetherStalkTile.cpp | 122 + Minecraft.World/NetherStalkTile.h | 33 + Minecraft.World/Node.cpp | 75 + Minecraft.World/Node.h | 38 + Minecraft.World/NonTameRandomTargetGoal.cpp | 14 + Minecraft.World/NonTameRandomTargetGoal.h | 16 + Minecraft.World/NormalDimension.h | 6 + Minecraft.World/NotGateTile.cpp | 247 + Minecraft.World/NotGateTile.h | 67 + Minecraft.World/Npc.cpp | 4 + Minecraft.World/Npc.h | 11 + Minecraft.World/NumberFormaters.h | 35 + Minecraft.World/ObsidianTile.cpp | 16 + Minecraft.World/ObsidianTile.h | 12 + Minecraft.World/OceanBiome.h | 14 + Minecraft.World/OcelotSitOnTileGoal.cpp | 127 + Minecraft.World/OcelotSitOnTileGoal.h | 37 + Minecraft.World/OfferFlowerGoal.cpp | 44 + Minecraft.World/OfferFlowerGoal.h | 25 + Minecraft.World/OldChunkStorage.cpp | 594 + Minecraft.World/OldChunkStorage.h | 57 + Minecraft.World/OpenDoorGoal.cpp | 35 + Minecraft.World/OpenDoorGoal.h | 18 + Minecraft.World/OreFeature.cpp | 127 + Minecraft.World/OreFeature.h | 19 + Minecraft.World/OreRecipies.cpp | 75 + Minecraft.World/OreRecipies.h | 17 + Minecraft.World/OreTile.cpp | 77 + Minecraft.World/OreTile.h | 17 + Minecraft.World/OutputStream.h | 14 + Minecraft.World/OwnerHurtByTargetGoal.cpp | 25 + Minecraft.World/OwnerHurtByTargetGoal.h | 18 + Minecraft.World/OwnerHurtTargetGoal.cpp | 25 + Minecraft.World/OwnerHurtTargetGoal.h | 18 + Minecraft.World/OxygenEnchantment.cpp | 22 + Minecraft.World/OxygenEnchantment.h | 13 + Minecraft.World/Ozelot.cpp | 333 + Minecraft.World/Ozelot.h | 76 + Minecraft.World/OzelotAttackGoal.cpp | 61 + Minecraft.World/OzelotAttackGoal.h | 25 + Minecraft.World/Packet.cpp | 596 + Minecraft.World/Packet.h | 113 + Minecraft.World/PacketListener.cpp | 451 + Minecraft.World/PacketListener.h | 211 + Minecraft.World/Painting.cpp | 148 + Minecraft.World/Painting.h | 117 + Minecraft.World/PanicGoal.cpp | 35 + Minecraft.World/PanicGoal.h | 20 + Minecraft.World/ParticleTypes.h | 56 + Minecraft.World/Path.cpp | 116 + Minecraft.World/Path.h | 31 + Minecraft.World/PathFinder.cpp | 271 + Minecraft.World/PathFinder.h | 54 + Minecraft.World/PathNavigation.cpp | 376 + Minecraft.World/PathNavigation.h | 67 + Minecraft.World/PathfinderMob.cpp | 264 + Minecraft.World/PathfinderMob.h | 49 + Minecraft.World/PerformanceTimer.cpp | 35 + Minecraft.World/PerformanceTimer.h | 13 + Minecraft.World/PerlinNoise.cpp | 98 + Minecraft.World/PerlinNoise.h | 24 + Minecraft.World/PerlinSimplexNoise.cpp | 115 + Minecraft.World/PerlinSimplexNoise.h | 23 + Minecraft.World/PickaxeItem.cpp | 62 + Minecraft.World/PickaxeItem.h | 20 + Minecraft.World/Pig.cpp | 192 + Minecraft.World/Pig.h | 58 + Minecraft.World/PigZombie.cpp | 202 + Minecraft.World/PigZombie.h | 60 + Minecraft.World/PineFeature.cpp | 102 + Minecraft.World/PineFeature.h | 8 + Minecraft.World/PistonBaseTile.cpp | 628 + Minecraft.World/PistonBaseTile.h | 71 + Minecraft.World/PistonExtensionTile.cpp | 210 + Minecraft.World/PistonExtensionTile.h | 31 + Minecraft.World/PistonMovingPiece.cpp | 211 + Minecraft.World/PistonMovingPiece.h | 37 + Minecraft.World/PistonPieceEntity.cpp | 215 + Minecraft.World/PistonPieceEntity.h | 40 + Minecraft.World/PistonTileItem.cpp | 14 + Minecraft.World/PistonTileItem.h | 12 + Minecraft.World/PlainsBiome.cpp | 9 + Minecraft.World/PlainsBiome.h | 10 + Minecraft.World/PlayGoal.cpp | 86 + Minecraft.World/PlayGoal.h | 22 + Minecraft.World/Player.cpp | 3002 ++ Minecraft.World/Player.h | 551 + Minecraft.World/PlayerAbilitiesPacket.cpp | 137 + Minecraft.World/PlayerAbilitiesPacket.h | 50 + Minecraft.World/PlayerActionPacket.cpp | 58 + Minecraft.World/PlayerActionPacket.h | 31 + Minecraft.World/PlayerCommandPacket.cpp | 51 + Minecraft.World/PlayerCommandPacket.h | 37 + Minecraft.World/PlayerEnderChestContainer.cpp | 72 + Minecraft.World/PlayerEnderChestContainer.h | 21 + Minecraft.World/PlayerIO.h | 22 + Minecraft.World/PlayerInfoPacket.cpp | 61 + Minecraft.World/PlayerInfoPacket.h | 32 + Minecraft.World/PlayerInputPacket.cpp | 87 + Minecraft.World/PlayerInputPacket.h | 36 + Minecraft.World/PortalForcer.cpp | 381 + Minecraft.World/PortalForcer.h | 21 + Minecraft.World/PortalMaterial.h | 12 + Minecraft.World/PortalTile.cpp | 246 + Minecraft.World/PortalTile.h | 25 + Minecraft.World/Pos.cpp | 248 + Minecraft.World/Pos.h | 97 + Minecraft.World/PotatoTile.cpp | 60 + Minecraft.World/PotatoTile.h | 23 + Minecraft.World/PotionBrewing.cpp | 910 + Minecraft.World/PotionBrewing.h | 101 + Minecraft.World/PotionItem.cpp | 372 + Minecraft.World/PotionItem.h | 57 + Minecraft.World/PreLoginPacket.cpp | 119 + Minecraft.World/PreLoginPacket.h | 39 + Minecraft.World/PressurePlateTile.cpp | 211 + Minecraft.World/PressurePlateTile.h | 49 + Minecraft.World/PrimedTnt.cpp | 116 + Minecraft.World/PrimedTnt.h | 37 + Minecraft.World/ProgressListener.h | 15 + Minecraft.World/ProtectionEnchantment.cpp | 94 + Minecraft.World/ProtectionEnchantment.h | 33 + Minecraft.World/PumpkinFeature.cpp | 23 + Minecraft.World/PumpkinFeature.h | 9 + Minecraft.World/PumpkinTile.cpp | 169 + Minecraft.World/PumpkinTile.h | 31 + Minecraft.World/QuartzBlockTile.cpp | 122 + Minecraft.World/QuartzBlockTile.h | 47 + Minecraft.World/RailTile.cpp | 676 + Minecraft.World/RailTile.h | 84 + Minecraft.World/RainforestBiome.cpp | 16 + Minecraft.World/RainforestBiome.h | 9 + Minecraft.World/Random.cpp | 106 + Minecraft.World/Random.h | 23 + Minecraft.World/RandomLevelSource.cpp | 780 + Minecraft.World/RandomLevelSource.h | 92 + Minecraft.World/RandomLookAroundGoal.cpp | 37 + Minecraft.World/RandomLookAroundGoal.h | 19 + Minecraft.World/RandomPos.cpp | 88 + Minecraft.World/RandomPos.h | 17 + .../RandomScatteredLargeFeature.cpp | 84 + Minecraft.World/RandomScatteredLargeFeature.h | 22 + Minecraft.World/RandomStrollGoal.cpp | 60 + Minecraft.World/RandomStrollGoal.h | 20 + Minecraft.World/Rarity.cpp | 12 + Minecraft.World/Rarity.h | 15 + Minecraft.World/ReadMe.txt | 30 + Minecraft.World/ReadOnlyChunkCache.cpp | 100 + Minecraft.World/ReadOnlyChunkCache.h | 39 + Minecraft.World/Reader.h | 11 + Minecraft.World/Recipes.cpp | 1220 + Minecraft.World/Recipes.h | 111 + Minecraft.World/Recipy.h | 55 + Minecraft.World/RecordPlayerTile.cpp | 100 + Minecraft.World/RecordPlayerTile.h | 68 + Minecraft.World/RecordingItem.cpp | 64 + Minecraft.World/RecordingItem.h | 23 + Minecraft.World/RedStoneDustTile.cpp | 431 + Minecraft.World/RedStoneDustTile.h | 61 + Minecraft.World/RedStoneItem.cpp | 40 + Minecraft.World/RedStoneItem.h | 13 + Minecraft.World/RedStoneOreTile.cpp | 128 + Minecraft.World/RedStoneOreTile.h | 34 + Minecraft.World/RedlightTile.cpp | 78 + Minecraft.World/RedlightTile.h | 19 + Minecraft.World/ReedTile.cpp | 117 + Minecraft.World/ReedTile.h | 52 + Minecraft.World/ReedsFeature.cpp | 46 + Minecraft.World/ReedsFeature.h | 9 + Minecraft.World/Reference.h | 10 + Minecraft.World/Region.cpp | 364 + Minecraft.World/Region.h | 51 + Minecraft.World/RegionFile.cpp | 497 + Minecraft.World/RegionFile.h | 97 + Minecraft.World/RegionFileCache.cpp | 122 + Minecraft.World/RegionFileCache.h | 35 + Minecraft.World/RegionHillsLayer.cpp | 78 + Minecraft.World/RegionHillsLayer.h | 11 + Minecraft.World/RemoveEntitiesPacket.cpp | 56 + Minecraft.World/RemoveEntitiesPacket.h | 27 + Minecraft.World/RemoveMobEffectPacket.cpp | 39 + Minecraft.World/RemoveMobEffectPacket.h | 23 + Minecraft.World/RepairContainer.cpp | 14 + Minecraft.World/RepairContainer.h | 15 + Minecraft.World/RepairMenu.cpp | 403 + Minecraft.World/RepairMenu.h | 55 + Minecraft.World/RepairResultSlot.cpp | 75 + Minecraft.World/RepairResultSlot.h | 20 + Minecraft.World/RespawnPacket.cpp | 97 + Minecraft.World/RespawnPacket.h | 34 + Minecraft.World/RestrictOpenDoorGoal.cpp | 49 + Minecraft.World/RestrictOpenDoorGoal.h | 22 + Minecraft.World/RestrictSunGoal.cpp | 25 + Minecraft.World/RestrictSunGoal.h | 16 + Minecraft.World/ResultContainer.cpp | 64 + Minecraft.World/ResultContainer.h | 26 + Minecraft.World/ResultSlot.cpp | 102 + Minecraft.World/ResultSlot.h | 26 + Minecraft.World/RiverBiome.h | 14 + Minecraft.World/RiverInitLayer.cpp | 24 + Minecraft.World/RiverInitLayer.h | 11 + Minecraft.World/RiverLayer.cpp | 40 + Minecraft.World/RiverLayer.h | 10 + Minecraft.World/RiverMixerLayer.cpp | 47 + Minecraft.World/RiverMixerLayer.h | 16 + Minecraft.World/Rotate.cpp | 15 + Minecraft.World/Rotate.h | 15 + Minecraft.World/RotateHeadPacket.cpp | 51 + Minecraft.World/RotateHeadPacket.h | 27 + Minecraft.World/SaddleItem.cpp | 31 + Minecraft.World/SaddleItem.h | 13 + Minecraft.World/SandFeature.cpp | 58 + Minecraft.World/SandFeature.h | 14 + Minecraft.World/SandStoneTile.cpp | 52 + Minecraft.World/SandStoneTile.h | 38 + Minecraft.World/Sapling.cpp | 166 + Minecraft.World/Sapling.h | 50 + Minecraft.World/SaplingTileItem.cpp | 31 + Minecraft.World/SaplingTileItem.h | 16 + Minecraft.World/SavedData.cpp | 24 + Minecraft.World/SavedData.h | 25 + Minecraft.World/SavedDataStorage.cpp | 211 + Minecraft.World/SavedDataStorage.h | 35 + Minecraft.World/Scale.cpp | 14 + Minecraft.World/Scale.h | 15 + Minecraft.World/ScatteredFeaturePieces.cpp | 537 + Minecraft.World/ScatteredFeaturePieces.h | 67 + Minecraft.World/SeedFoodItem.cpp | 31 + Minecraft.World/SeedFoodItem.h | 15 + Minecraft.World/SeedItem.cpp | 36 + Minecraft.World/SeedItem.h | 16 + Minecraft.World/Sensing.cpp | 35 + Minecraft.World/Sensing.h | 15 + Minecraft.World/ServerAuthDataPacket.h | 58 + .../ServerSettingsChangedPacket.cpp | 52 + Minecraft.World/ServerSettingsChangedPacket.h | 31 + Minecraft.World/SetCarriedItemPacket.cpp | 47 + Minecraft.World/SetCarriedItemPacket.h | 24 + Minecraft.World/SetCreativeModeSlotPacket.cpp | 42 + Minecraft.World/SetCreativeModeSlotPacket.h | 23 + Minecraft.World/SetEntityDataPacket.cpp | 64 + Minecraft.World/SetEntityDataPacket.h | 31 + Minecraft.World/SetEntityMotionPacket.cpp | 113 + Minecraft.World/SetEntityMotionPacket.h | 31 + Minecraft.World/SetEquippedItemPacket.cpp | 69 + Minecraft.World/SetEquippedItemPacket.h | 33 + Minecraft.World/SetExperiencePacket.cpp | 59 + Minecraft.World/SetExperiencePacket.h | 26 + Minecraft.World/SetHealthPacket.cpp | 66 + Minecraft.World/SetHealthPacket.h | 30 + Minecraft.World/SetRidingPacket.cpp | 53 + Minecraft.World/SetRidingPacket.h | 25 + Minecraft.World/SetSpawnPositionPacket.cpp | 60 + Minecraft.World/SetSpawnPositionPacket.h | 25 + Minecraft.World/SetTimePacket.cpp | 52 + Minecraft.World/SetTimePacket.h | 25 + Minecraft.World/ShapedRecipy.cpp | 230 + Minecraft.World/ShapedRecipy.h | 32 + Minecraft.World/ShapelessRecipy.cpp | 182 + Minecraft.World/ShapelessRecipy.h | 23 + Minecraft.World/SharedConstants.cpp | 51 + Minecraft.World/SharedConstants.h | 32 + Minecraft.World/SharedKeyPacket.h | 63 + Minecraft.World/ShearsItem.cpp | 38 + Minecraft.World/ShearsItem.h | 13 + Minecraft.World/Sheep.cpp | 337 + Minecraft.World/Sheep.h | 86 + Minecraft.World/ShoreLayer.cpp | 74 + Minecraft.World/ShoreLayer.h | 9 + Minecraft.World/ShortTag.h | 36 + Minecraft.World/ShovelItem.cpp | 33 + Minecraft.World/ShovelItem.h | 15 + Minecraft.World/SignItem.cpp | 59 + Minecraft.World/SignItem.h | 12 + Minecraft.World/SignTile.cpp | 129 + Minecraft.World/SignTile.h | 38 + Minecraft.World/SignTileEntity.cpp | 198 + Minecraft.World/SignTileEntity.h | 49 + Minecraft.World/SignUpdatePacket.cpp | 71 + Minecraft.World/SignUpdatePacket.h | 26 + Minecraft.World/Silverfish.cpp | 211 + Minecraft.World/Silverfish.h | 49 + Minecraft.World/SimpleContainer.cpp | 110 + Minecraft.World/SimpleContainer.h | 42 + Minecraft.World/SimplexNoise.cpp | 476 + Minecraft.World/SimplexNoise.h | 40 + Minecraft.World/SitGoal.cpp | 45 + Minecraft.World/SitGoal.h | 18 + Minecraft.World/Skeleton.cpp | 154 + Minecraft.World/Skeleton.h | 39 + Minecraft.World/SkullItem.cpp | 141 + Minecraft.World/SkullItem.h | 29 + Minecraft.World/SkullTile.cpp | 270 + Minecraft.World/SkullTile.h | 44 + Minecraft.World/SkullTileEntity.cpp | 72 + Minecraft.World/SkullTileEntity.h | 36 + Minecraft.World/SkyIslandDimension.cpp | 63 + Minecraft.World/Slime.cpp | 287 + Minecraft.World/Slime.h | 78 + Minecraft.World/Slot.cpp | 163 + Minecraft.World/Slot.h | 41 + Minecraft.World/SmallFireball.cpp | 80 + Minecraft.World/SmallFireball.h | 24 + Minecraft.World/SmoothFloat.cpp | 29 + Minecraft.World/SmoothFloat.h | 13 + Minecraft.World/SmoothLayer.cpp | 45 + Minecraft.World/SmoothLayer.h | 11 + Minecraft.World/SmoothStoneBrickTile.cpp | 43 + Minecraft.World/SmoothStoneBrickTile.h | 33 + Minecraft.World/SmoothStoneBrickTileItem.cpp | 32 + Minecraft.World/SmoothStoneBrickTileItem.h | 17 + Minecraft.World/SmoothZoomLayer.cpp | 61 + Minecraft.World/SmoothZoomLayer.h | 12 + Minecraft.World/SnowMan.cpp | 97 + Minecraft.World/SnowMan.h | 21 + Minecraft.World/SnowTile.cpp | 35 + Minecraft.World/SnowTile.h | 20 + Minecraft.World/Snowball.cpp | 52 + Minecraft.World/Snowball.h | 24 + Minecraft.World/SnowballItem.cpp | 23 + Minecraft.World/SnowballItem.h | 12 + Minecraft.World/Socket.cpp | 534 + Minecraft.World/Socket.h | 134 + Minecraft.World/SocketAddress.h | 6 + Minecraft.World/SoundTypes.h | 304 + Minecraft.World/SparseDataStorage.cpp | 625 + Minecraft.World/SparseDataStorage.h | 84 + Minecraft.World/SparseLightStorage.cpp | 642 + Minecraft.World/SparseLightStorage.h | 87 + Minecraft.World/Spider.cpp | 192 + Minecraft.World/Spider.h | 45 + Minecraft.World/SpikeFeature.cpp | 179 + Minecraft.World/SpikeFeature.h | 14 + Minecraft.World/Sponge.cpp | 11 + Minecraft.World/Sponge.h | 13 + Minecraft.World/SpringFeature.cpp | 51 + Minecraft.World/SpringFeature.h | 14 + Minecraft.World/SpringTile.cpp | 29 + Minecraft.World/SpringTile.h | 17 + Minecraft.World/SpruceFeature.cpp | 116 + Minecraft.World/SpruceFeature.h | 9 + Minecraft.World/Squid.cpp | 189 + Minecraft.World/Squid.h | 52 + Minecraft.World/StairTile.cpp | 567 + Minecraft.World/StairTile.h | 106 + Minecraft.World/Stat.cpp | 115 + Minecraft.World/Stat.h | 61 + Minecraft.World/StatFormatter.h | 8 + Minecraft.World/Stats.cpp | 557 + Minecraft.World/Stats.h | 94 + Minecraft.World/StemTile.cpp | 234 + Minecraft.World/StemTile.h | 48 + Minecraft.World/StoneMonsterTile.cpp | 114 + Minecraft.World/StoneMonsterTile.h | 38 + Minecraft.World/StoneMonsterTileItem.cpp | 30 + Minecraft.World/StoneMonsterTileItem.h | 16 + Minecraft.World/StoneSlabTile.cpp | 84 + Minecraft.World/StoneSlabTile.h | 39 + Minecraft.World/StoneSlabTileItem.cpp | 140 + Minecraft.World/StoneSlabTileItem.h | 24 + Minecraft.World/StoneTile.cpp | 11 + Minecraft.World/StoneTile.h | 11 + Minecraft.World/StringHelpers.cpp | 133 + Minecraft.World/StringHelpers.h | 40 + Minecraft.World/StringTag.h | 42 + Minecraft.World/StrongholdFeature.cpp | 224 + Minecraft.World/StrongholdFeature.h | 45 + Minecraft.World/StrongholdPieces.cpp | 1517 + Minecraft.World/StrongholdPieces.h | 395 + Minecraft.World/StructureFeature.cpp | 208 + Minecraft.World/StructureFeature.h | 58 + Minecraft.World/StructurePiece.cpp | 822 + Minecraft.World/StructurePiece.h | 117 + Minecraft.World/StructureRecipies.cpp | 128 + Minecraft.World/StructureRecipies.h | 7 + Minecraft.World/StructureStart.cpp | 111 + Minecraft.World/StructureStart.h | 25 + Minecraft.World/SwampBiome.cpp | 40 + Minecraft.World/SwampBiome.h | 18 + Minecraft.World/SwampRiversLayer.cpp | 34 + Minecraft.World/SwampRiversLayer.h | 11 + Minecraft.World/SwampTreeFeature.cpp | 132 + Minecraft.World/SwampTreeFeature.h | 11 + Minecraft.World/SwellGoal.cpp | 54 + Minecraft.World/SwellGoal.h | 20 + Minecraft.World/SynchedEntityData.cpp | 558 + Minecraft.World/SynchedEntityData.h | 127 + Minecraft.World/Synth.cpp | 15 + Minecraft.World/Synth.h | 9 + Minecraft.World/System.h | 39 + Minecraft.World/Tag.cpp | 181 + Minecraft.World/Tag.h | 45 + Minecraft.World/TaigaBiome.cpp | 22 + Minecraft.World/TaigaBiome.h | 10 + Minecraft.World/TakeFlowerGoal.cpp | 82 + Minecraft.World/TakeFlowerGoal.h | 21 + Minecraft.World/TakeItemEntityPacket.cpp | 41 + Minecraft.World/TakeItemEntityPacket.h | 22 + Minecraft.World/TallGrass.cpp | 119 + Minecraft.World/TallGrass.h | 43 + Minecraft.World/TallGrassFeature.cpp | 33 + Minecraft.World/TallGrassFeature.h | 14 + Minecraft.World/TamableAnimal.cpp | 159 + Minecraft.World/TamableAnimal.h | 38 + Minecraft.World/TargetGoal.cpp | 113 + Minecraft.World/TargetGoal.h | 44 + Minecraft.World/TeleportEntityPacket.cpp | 91 + Minecraft.World/TeleportEntityPacket.h | 27 + Minecraft.World/TemperatureLayer.cpp | 20 + Minecraft.World/TemperatureLayer.h | 11 + Minecraft.World/TemperatureMixerLayer.cpp | 23 + Minecraft.World/TemperatureMixerLayer.h | 15 + Minecraft.World/TemptGoal.cpp | 91 + Minecraft.World/TemptGoal.h | 27 + .../TextureAndGeometryChangePacket.cpp | 53 + .../TextureAndGeometryChangePacket.h | 25 + Minecraft.World/TextureAndGeometryPacket.cpp | 189 + Minecraft.World/TextureAndGeometryPacket.h | 35 + Minecraft.World/TextureChangePacket.cpp | 46 + Minecraft.World/TextureChangePacket.h | 30 + Minecraft.World/TexturePacket.cpp | 66 + Minecraft.World/TexturePacket.h | 25 + Minecraft.World/TheEndBiome.cpp | 26 + Minecraft.World/TheEndBiome.h | 11 + Minecraft.World/TheEndBiomeDecorator.cpp | 71 + Minecraft.World/TheEndBiomeDecorator.h | 24 + Minecraft.World/TheEndDimension.cpp | 91 + Minecraft.World/TheEndDimension.h | 20 + .../TheEndLevelRandomLevelSource.cpp | 421 + .../TheEndLevelRandomLevelSource.h | 60 + Minecraft.World/TheEndPortal.cpp | 126 + Minecraft.World/TheEndPortal.h | 27 + Minecraft.World/TheEndPortalFrameTile.cpp | 83 + Minecraft.World/TheEndPortalFrameTile.h | 26 + Minecraft.World/TheEndPortalTileEntity.cpp | 10 + Minecraft.World/TheEndPortalTileEntity.h | 12 + Minecraft.World/ThinFenceTile.cpp | 154 + Minecraft.World/ThinFenceTile.h | 32 + Minecraft.World/ThornsEnchantment.cpp | 77 + Minecraft.World/ThornsEnchantment.h | 20 + Minecraft.World/ThreadName.cpp | 41 + Minecraft.World/ThreadName.h | 3 + Minecraft.World/Throwable.cpp | 281 + Minecraft.World/Throwable.h | 60 + Minecraft.World/ThrownEgg.cpp | 67 + Minecraft.World/ThrownEgg.h | 23 + Minecraft.World/ThrownEnderpearl.cpp | 62 + Minecraft.World/ThrownEnderpearl.h | 19 + Minecraft.World/ThrownExpBottle.cpp | 55 + Minecraft.World/ThrownExpBottle.h | 22 + Minecraft.World/ThrownPotion.cpp | 136 + Minecraft.World/ThrownPotion.h | 43 + Minecraft.World/TickNextTickData.cpp | 69 + Minecraft.World/TickNextTickData.h | 46 + Minecraft.World/Tile.cpp | 1632 + Minecraft.World/Tile.h | 648 + Minecraft.World/TileDestructionPacket.cpp | 85 + Minecraft.World/TileDestructionPacket.h | 35 + Minecraft.World/TileEntity.cpp | 211 + Minecraft.World/TileEntity.h | 74 + Minecraft.World/TileEntityDataPacket.cpp | 65 + Minecraft.World/TileEntityDataPacket.h | 36 + Minecraft.World/TileEventData.cpp | 48 + Minecraft.World/TileEventData.h | 21 + Minecraft.World/TileEventPacket.cpp | 56 + Minecraft.World/TileEventPacket.h | 22 + Minecraft.World/TileItem.cpp | 221 + Minecraft.World/TileItem.h | 44 + Minecraft.World/TilePlanterItem.cpp | 80 + Minecraft.World/TilePlanterItem.h | 15 + Minecraft.World/TilePos.cpp | 29 + Minecraft.World/TilePos.h | 27 + Minecraft.World/TileUpdatePacket.cpp | 92 + Minecraft.World/TileUpdatePacket.h | 23 + Minecraft.World/TimeCommand.cpp | 80 + Minecraft.World/TimeCommand.h | 17 + Minecraft.World/TntTile.cpp | 120 + Minecraft.World/TntTile.h | 31 + Minecraft.World/ToggleDownfallCommand.cpp | 30 + Minecraft.World/ToggleDownfallCommand.h | 17 + Minecraft.World/ToolRecipies.cpp | 128 + Minecraft.World/ToolRecipies.h | 24 + Minecraft.World/TopSnowTile.cpp | 182 + Minecraft.World/TopSnowTile.h | 66 + Minecraft.World/TorchTile.cpp | 238 + Minecraft.World/TorchTile.h | 36 + Minecraft.World/TownFeature.h | 5 + Minecraft.World/TradeItemPacket.cpp | 41 + Minecraft.World/TradeItemPacket.h | 32 + Minecraft.World/TradeWithPlayerGoal.cpp | 51 + Minecraft.World/TradeWithPlayerGoal.h | 18 + Minecraft.World/TransparentTile.cpp | 25 + Minecraft.World/TransparentTile.h | 14 + Minecraft.World/TrapDoorTile.cpp | 209 + Minecraft.World/TrapDoorTile.h | 87 + Minecraft.World/TrapMenu.cpp | 81 + Minecraft.World/TrapMenu.h | 22 + Minecraft.World/TreeFeature.cpp | 179 + Minecraft.World/TreeFeature.h | 20 + Minecraft.World/TreeTile.cpp | 141 + Minecraft.World/TreeTile.h | 55 + Minecraft.World/TreeTileItem.cpp | 31 + Minecraft.World/TreeTileItem.h | 18 + Minecraft.World/TripWireSourceTile.cpp | 359 + Minecraft.World/TripWireSourceTile.h | 43 + Minecraft.World/TripWireTile.cpp | 221 + Minecraft.World/TripWireTile.h | 43 + Minecraft.World/UntouchingEnchantment.cpp | 34 + Minecraft.World/UntouchingEnchantment.h | 15 + .../UpdateGameRuleProgressPacket.cpp | 75 + .../UpdateGameRuleProgressPacket.h | 26 + Minecraft.World/UpdateMobEffectPacket.cpp | 60 + Minecraft.World/UpdateMobEffectPacket.h | 28 + Minecraft.World/UpdateProgressPacket.cpp | 37 + Minecraft.World/UpdateProgressPacket.h | 25 + Minecraft.World/UseAnim.h | 10 + Minecraft.World/UseItemPacket.cpp | 112 + Minecraft.World/UseItemPacket.h | 36 + Minecraft.World/Vec3.cpp | 265 + Minecraft.World/Vec3.h | 59 + Minecraft.World/Village.cpp | 512 + Minecraft.World/Village.h | 81 + Minecraft.World/VillageFeature.cpp | 144 + Minecraft.World/VillageFeature.h | 31 + Minecraft.World/VillagePieces.cpp | 1847 + Minecraft.World/VillagePieces.h | 353 + Minecraft.World/VillageSiege.cpp | 169 + Minecraft.World/VillageSiege.h | 28 + Minecraft.World/Villager.cpp | 782 + Minecraft.World/Villager.h | 149 + Minecraft.World/VillagerGolem.cpp | 240 + Minecraft.World/VillagerGolem.h | 64 + Minecraft.World/Villages.cpp | 253 + Minecraft.World/Villages.h | 47 + Minecraft.World/VineTile.cpp | 387 + Minecraft.World/VineTile.h | 38 + Minecraft.World/VinesFeature.cpp | 39 + Minecraft.World/VinesFeature.h | 12 + Minecraft.World/VoronoiZoom.cpp | 122 + Minecraft.World/VoronoiZoom.h | 15 + Minecraft.World/WallTile.cpp | 189 + Minecraft.World/WallTile.h | 31 + Minecraft.World/WaterAnimal.cpp | 42 + Minecraft.World/WaterAnimal.h | 18 + Minecraft.World/WaterColor.cpp | 23 + Minecraft.World/WaterColor.h | 14 + Minecraft.World/WaterLevelChunk.cpp | 159 + Minecraft.World/WaterLevelChunk.h | 45 + Minecraft.World/WaterLilyTile.cpp | 76 + Minecraft.World/WaterLilyTile.h | 24 + Minecraft.World/WaterLilyTileItem.cpp | 78 + Minecraft.World/WaterLilyTileItem.h | 14 + Minecraft.World/WaterWorkerEnchantment.cpp | 22 + Minecraft.World/WaterWorkerEnchantment.h | 13 + Minecraft.World/WaterlilyFeature.cpp | 23 + Minecraft.World/WaterlilyFeature.h | 7 + Minecraft.World/WeaponItem.cpp | 87 + Minecraft.World/WeaponItem.h | 28 + Minecraft.World/WeaponRecipies.cpp | 107 + Minecraft.World/WeaponRecipies.h | 22 + Minecraft.World/WebMaterial.h | 9 + Minecraft.World/WebTile.cpp | 53 + Minecraft.World/WebTile.h | 31 + Minecraft.World/WeighedRandom.cpp | 72 + Minecraft.World/WeighedRandom.h | 28 + Minecraft.World/WeighedTreasure.cpp | 86 + Minecraft.World/WeighedTreasure.h | 19 + Minecraft.World/Wolf.cpp | 550 + Minecraft.World/Wolf.h | 86 + Minecraft.World/WoodSlabTile.cpp | 60 + Minecraft.World/WoodSlabTile.h | 28 + Minecraft.World/WoodTile.cpp | 56 + Minecraft.World/WoodTile.h | 26 + Minecraft.World/WoolCarpetTile.cpp | 111 + Minecraft.World/WoolCarpetTile.h | 37 + Minecraft.World/WorkbenchTile.cpp | 44 + Minecraft.World/WorkbenchTile.h | 26 + Minecraft.World/XZPacket.cpp | 52 + Minecraft.World/XZPacket.h | 30 + Minecraft.World/Zombie.cpp | 383 + Minecraft.World/Zombie.h | 88 + Minecraft.World/ZoneFile.cpp | 92 + Minecraft.World/ZoneFile.h | 42 + Minecraft.World/ZoneIo.cpp | 48 + Minecraft.World/ZoneIo.h | 19 + Minecraft.World/ZonedChunkStorage.cpp | 264 + Minecraft.World/ZonedChunkStorage.h | 53 + Minecraft.World/ZoomLayer.cpp | 92 + Minecraft.World/ZoomLayer.h | 18 + Minecraft.World/com.mojang.nbt.h | 1 + Minecraft.World/compression.cpp | 546 + Minecraft.World/compression.h | 86 + .../net.minecraft.commands.common.h | 10 + Minecraft.World/net.minecraft.commands.h | 7 + Minecraft.World/net.minecraft.h | 6 + Minecraft.World/net.minecraft.locale.h | 4 + Minecraft.World/net.minecraft.network.h | 3 + .../net.minecraft.network.packet.h | 102 + Minecraft.World/net.minecraft.stats.h | 10 + .../net.minecraft.world.ContainerListener.h | 18 + .../net.minecraft.world.damagesource.h | 5 + Minecraft.World/net.minecraft.world.effect.h | 5 + .../net.minecraft.world.entity.ai.control.h | 7 + .../net.minecraft.world.entity.ai.goal.h | 41 + ...et.minecraft.world.entity.ai.goal.target.h | 9 + ...net.minecraft.world.entity.ai.navigation.h | 3 + .../net.minecraft.world.entity.ai.sensing.h | 3 + .../net.minecraft.world.entity.ai.util.h | 3 + .../net.minecraft.world.entity.ai.village.h | 6 + .../net.minecraft.world.entity.animal.h | 20 + ....minecraft.world.entity.boss.enderdragon.h | 5 + .../net.minecraft.world.entity.boss.h | 4 + .../net.minecraft.world.entity.global.h | 4 + Minecraft.World/net.minecraft.world.entity.h | 26 + .../net.minecraft.world.entity.item.h | 7 + .../net.minecraft.world.entity.monster.h | 21 + .../net.minecraft.world.entity.npc.h | 5 + .../net.minecraft.world.entity.player.h | 5 + .../net.minecraft.world.entity.projectile.h | 18 + Minecraft.World/net.minecraft.world.food.h | 4 + Minecraft.World/net.minecraft.world.h | 13 + ...ecraft.world.inventory.ContainerListener.h | 21 + .../net.minecraft.world.inventory.h | 27 + .../net.minecraft.world.item.alchemy.h | 3 + .../net.minecraft.world.item.crafting.h | 15 + .../net.minecraft.world.item.enchantment.h | 24 + Minecraft.World/net.minecraft.world.item.h | 80 + .../net.minecraft.world.item.trading.h | 5 + .../net.minecraft.world.level.biome.h | 32 + .../net.minecraft.world.level.chunk.h | 8 + .../net.minecraft.world.level.chunk.storage.h | 13 + .../net.minecraft.world.level.dimension.h | 6 + Minecraft.World/net.minecraft.world.level.h | 25 + ...t.minecraft.world.level.levelgen.feature.h | 37 + .../net.minecraft.world.level.levelgen.h | 15 + ...minecraft.world.level.levelgen.structure.h | 16 + ...net.minecraft.world.level.levelgen.synth.h | 12 + .../net.minecraft.world.level.material.h | 8 + ...net.minecraft.world.level.newbiome.layer.h | 28 + .../net.minecraft.world.level.pathfinder.h | 6 + .../net.minecraft.world.level.saveddata.h | 4 + .../net.minecraft.world.level.storage.h | 16 + .../net.minecraft.world.level.tile.entity.h | 15 + .../net.minecraft.world.level.tile.h | 114 + .../net.minecraft.world.level.tile.piston.h | 6 + Minecraft.World/net.minecraft.world.phys.h | 3 + Minecraft.World/stdafx.cpp | 8 + Minecraft.World/stdafx.h | 247 + Minecraft.World/system.cpp | 200 + Minecraft.World/x64headers/extraX64.h | 650 + Minecraft.World/x64headers/qnet.h | 0 Minecraft.World/x64headers/xmcore.h | 0 Minecraft.World/x64headers/xrnm.h | 0 Minecraft.World/x64headers/xsocialpost.h | 0 Minecraft.World/x64headers/xuiapp.h | 0 Minecraft.World/x64headers/xuiresource.h | 0 MinecraftConsoles.sln | 133 + 2946 files changed, 577259 insertions(+) create mode 100644 .gitignore create mode 100644 Minecraft.Client/AbstractContainerScreen.cpp create mode 100644 Minecraft.Client/AbstractContainerScreen.h create mode 100644 Minecraft.Client/AbstractTexturePack.cpp create mode 100644 Minecraft.Client/AbstractTexturePack.h create mode 100644 Minecraft.Client/AchievementPopup.cpp create mode 100644 Minecraft.Client/AchievementPopup.h create mode 100644 Minecraft.Client/AchievementScreen.cpp create mode 100644 Minecraft.Client/AchievementScreen.h create mode 100644 Minecraft.Client/AllowAllCuller.cpp create mode 100644 Minecraft.Client/AllowAllCuller.h create mode 100644 Minecraft.Client/ArchiveFile.cpp create mode 100644 Minecraft.Client/ArchiveFile.h create mode 100644 Minecraft.Client/ArrowRenderer.cpp create mode 100644 Minecraft.Client/ArrowRenderer.h create mode 100644 Minecraft.Client/BlazeModel.cpp create mode 100644 Minecraft.Client/BlazeModel.h create mode 100644 Minecraft.Client/BlazeRenderer.cpp create mode 100644 Minecraft.Client/BlazeRenderer.h create mode 100644 Minecraft.Client/BoatModel.cpp create mode 100644 Minecraft.Client/BoatModel.h create mode 100644 Minecraft.Client/BoatRenderer.cpp create mode 100644 Minecraft.Client/BoatRenderer.h create mode 100644 Minecraft.Client/BookModel.cpp create mode 100644 Minecraft.Client/BookModel.h create mode 100644 Minecraft.Client/BreakingItemParticle.cpp create mode 100644 Minecraft.Client/BreakingItemParticle.h create mode 100644 Minecraft.Client/BubbleParticle.cpp create mode 100644 Minecraft.Client/BubbleParticle.h create mode 100644 Minecraft.Client/BufferedImage.cpp create mode 100644 Minecraft.Client/BufferedImage.h create mode 100644 Minecraft.Client/Button.cpp create mode 100644 Minecraft.Client/Button.h create mode 100644 Minecraft.Client/Camera.cpp create mode 100644 Minecraft.Client/Camera.h create mode 100644 Minecraft.Client/ChatScreen.cpp create mode 100644 Minecraft.Client/ChatScreen.h create mode 100644 Minecraft.Client/ChestModel.cpp create mode 100644 Minecraft.Client/ChestModel.h create mode 100644 Minecraft.Client/ChestRenderer.cpp create mode 100644 Minecraft.Client/ChestRenderer.h create mode 100644 Minecraft.Client/ChickenModel.cpp create mode 100644 Minecraft.Client/ChickenModel.h create mode 100644 Minecraft.Client/ChickenRenderer.cpp create mode 100644 Minecraft.Client/ChickenRenderer.h create mode 100644 Minecraft.Client/Chunk.cpp create mode 100644 Minecraft.Client/Chunk.h create mode 100644 Minecraft.Client/ClientConnection.cpp create mode 100644 Minecraft.Client/ClientConnection.h create mode 100644 Minecraft.Client/ClientConstants.cpp create mode 100644 Minecraft.Client/ClientConstants.h create mode 100644 Minecraft.Client/ClockTexture.cpp create mode 100644 Minecraft.Client/ClockTexture.h create mode 100644 Minecraft.Client/Common/App_Defines.h create mode 100644 Minecraft.Client/Common/App_enums.h create mode 100644 Minecraft.Client/Common/App_structs.h create mode 100644 Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp create mode 100644 Minecraft.Client/Common/Audio/Consoles_SoundEngine.h create mode 100644 Minecraft.Client/Common/Audio/SoundEngine.cpp create mode 100644 Minecraft.Client/Common/Audio/SoundEngine.h create mode 100644 Minecraft.Client/Common/Audio/SoundNames.cpp create mode 100644 Minecraft.Client/Common/BuildVer.h create mode 100644 Minecraft.Client/Common/C4JMemoryPool.h create mode 100644 Minecraft.Client/Common/C4JMemoryPoolAllocator.h create mode 100644 Minecraft.Client/Common/Colours/ColourTable.cpp create mode 100644 Minecraft.Client/Common/Colours/ColourTable.h create mode 100644 Minecraft.Client/Common/CommonMedia.sln create mode 100644 Minecraft.Client/Common/CommonMedia.vcxproj create mode 100644 Minecraft.Client/Common/CommonMedia.vcxproj.filters create mode 100644 Minecraft.Client/Common/ConsoleGameMode.cpp create mode 100644 Minecraft.Client/Common/ConsoleGameMode.h create mode 100644 Minecraft.Client/Common/Console_Awards_enum.h create mode 100644 Minecraft.Client/Common/Console_Debug_enum.h create mode 100644 Minecraft.Client/Common/Console_Utils.cpp create mode 100644 Minecraft.Client/Common/Consoles_App.cpp create mode 100644 Minecraft.Client/Common/Consoles_App.h create mode 100644 Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/BiomeOverride.cpp create mode 100644 Minecraft.Client/Common/GameRules/BiomeOverride.h create mode 100644 Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/ConsoleGameRules.h create mode 100644 Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h create mode 100644 Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp create mode 100644 Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h create mode 100644 Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h create mode 100644 Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp create mode 100644 Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h create mode 100644 Minecraft.Client/Common/GameRules/GameRule.cpp create mode 100644 Minecraft.Client/Common/GameRules/GameRule.h create mode 100644 Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/GameRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/GameRuleManager.cpp create mode 100644 Minecraft.Client/Common/GameRules/GameRuleManager.h create mode 100644 Minecraft.Client/Common/GameRules/GameRulesInstance.h create mode 100644 Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp create mode 100644 Minecraft.Client/Common/GameRules/LevelGenerationOptions.h create mode 100644 Minecraft.Client/Common/GameRules/LevelGenerators.cpp create mode 100644 Minecraft.Client/Common/GameRules/LevelGenerators.h create mode 100644 Minecraft.Client/Common/GameRules/LevelRules.cpp create mode 100644 Minecraft.Client/Common/GameRules/LevelRules.h create mode 100644 Minecraft.Client/Common/GameRules/LevelRuleset.cpp create mode 100644 Minecraft.Client/Common/GameRules/LevelRuleset.h create mode 100644 Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/StartFeature.cpp create mode 100644 Minecraft.Client/Common/GameRules/StartFeature.h create mode 100644 Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp create mode 100644 Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp create mode 100644 Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h create mode 100644 Minecraft.Client/Common/Leaderboards/LeaderboardManager.cpp create mode 100644 Minecraft.Client/Common/Leaderboards/LeaderboardManager.h create mode 100644 Minecraft.Client/Common/Minecraft_Macros.h create mode 100644 Minecraft.Client/Common/Network/GameNetworkManager.cpp create mode 100644 Minecraft.Client/Common/Network/GameNetworkManager.h create mode 100644 Minecraft.Client/Common/Network/NetworkPlayerInterface.h create mode 100644 Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h create mode 100644 Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp create mode 100644 Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h create mode 100644 Minecraft.Client/Common/Network/SessionInfo.h create mode 100644 Minecraft.Client/Common/Potion_Macros.h create mode 100644 Minecraft.Client/Common/Telemetry/TelemetryManager.cpp create mode 100644 Minecraft.Client/Common/Telemetry/TelemetryManager.h create mode 100644 Minecraft.Client/Common/Trial/TrialLevel.mcs create mode 100644 Minecraft.Client/Common/Trial/TrialMode.cpp create mode 100644 Minecraft.Client/Common/Trial/TrialMode.h create mode 100644 Minecraft.Client/Common/Tutorial/AreaConstraint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/AreaConstraint.h create mode 100644 Minecraft.Client/Common/Tutorial/AreaHint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/AreaHint.h create mode 100644 Minecraft.Client/Common/Tutorial/AreaTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/AreaTask.h create mode 100644 Minecraft.Client/Common/Tutorial/ChangeStateConstraint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/ChangeStateConstraint.h create mode 100644 Minecraft.Client/Common/Tutorial/ChoiceTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/ChoiceTask.h create mode 100644 Minecraft.Client/Common/Tutorial/CompleteUsingItemTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/CompleteUsingItemTask.h create mode 100644 Minecraft.Client/Common/Tutorial/ControllerTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/ControllerTask.h create mode 100644 Minecraft.Client/Common/Tutorial/CraftTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/CraftTask.h create mode 100644 Minecraft.Client/Common/Tutorial/DiggerItemHint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/DiggerItemHint.h create mode 100644 Minecraft.Client/Common/Tutorial/EffectChangedTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/EffectChangedTask.h create mode 100644 Minecraft.Client/Common/Tutorial/FullTutorial.cpp create mode 100644 Minecraft.Client/Common/Tutorial/FullTutorial.h create mode 100644 Minecraft.Client/Common/Tutorial/FullTutorialActiveTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/FullTutorialActiveTask.h create mode 100644 Minecraft.Client/Common/Tutorial/FullTutorialMode.cpp create mode 100644 Minecraft.Client/Common/Tutorial/FullTutorialMode.h create mode 100644 Minecraft.Client/Common/Tutorial/InfoTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/InfoTask.h create mode 100644 Minecraft.Client/Common/Tutorial/InputConstraint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/InputConstraint.h create mode 100644 Minecraft.Client/Common/Tutorial/LookAtEntityHint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/LookAtEntityHint.h create mode 100644 Minecraft.Client/Common/Tutorial/LookAtTileHint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/LookAtTileHint.h create mode 100644 Minecraft.Client/Common/Tutorial/PickupTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/PickupTask.h create mode 100644 Minecraft.Client/Common/Tutorial/ProcedureCompoundTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/ProcedureCompoundTask.h create mode 100644 Minecraft.Client/Common/Tutorial/ProgressFlagTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/ProgressFlagTask.h create mode 100644 Minecraft.Client/Common/Tutorial/StatTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/StatTask.h create mode 100644 Minecraft.Client/Common/Tutorial/StateChangeTask.h create mode 100644 Minecraft.Client/Common/Tutorial/TakeItemHint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/TakeItemHint.h create mode 100644 Minecraft.Client/Common/Tutorial/Tutorial create mode 100644 Minecraft.Client/Common/Tutorial/Tutorial.cpp create mode 100644 Minecraft.Client/Common/Tutorial/Tutorial.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialConstraint.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialConstraints.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialEnum.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialHint.cpp create mode 100644 Minecraft.Client/Common/Tutorial/TutorialHint.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialHints.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialMessage.cpp create mode 100644 Minecraft.Client/Common/Tutorial/TutorialMessage.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialMode.cpp create mode 100644 Minecraft.Client/Common/Tutorial/TutorialMode.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/TutorialTask.h create mode 100644 Minecraft.Client/Common/Tutorial/TutorialTasks.h create mode 100644 Minecraft.Client/Common/Tutorial/UseItemTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/UseItemTask.h create mode 100644 Minecraft.Client/Common/Tutorial/UseTileTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/UseTileTask.h create mode 100644 Minecraft.Client/Common/Tutorial/XuiCraftingTask.cpp create mode 100644 Minecraft.Client/Common/Tutorial/XuiCraftingTask.h create mode 100644 Minecraft.Client/Common/UI/IUIController.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_AbstractContainerMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_AnvilMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_AnvilMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_BrewingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_BrewingMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_ContainerMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_ContainerMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_CraftingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_CraftingMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_CreativeMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_CreativeMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_DispenserMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_DispenserMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_EnchantingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_EnchantingMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_FurnaceMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_FurnaceMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_InventoryMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_InventoryMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_PauseMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_PauseMenu.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_StartGame.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_StartGame.h create mode 100644 Minecraft.Client/Common/UI/IUIScene_TradingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/IUIScene_TradingMenu.h create mode 100644 Minecraft.Client/Common/UI/UI.h create mode 100644 Minecraft.Client/Common/UI/UIBitmapFont.cpp create mode 100644 Minecraft.Client/Common/UI/UIBitmapFont.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_Chat.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_Chat.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_DebugUIConsole.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_DebugUIConsole.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_DebugUIMarketingGuide.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_DebugUIMarketingGuide.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_Logo.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_Logo.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_MenuBackground.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_MenuBackground.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_Panorama.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_Panorama.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_PressStartToPlay.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_PressStartToPlay.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_Tooltips.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_Tooltips.h create mode 100644 Minecraft.Client/Common/UI/UIComponent_TutorialPopup.cpp create mode 100644 Minecraft.Client/Common/UI/UIComponent_TutorialPopup.h create mode 100644 Minecraft.Client/Common/UI/UIControl.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Base.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Base.h create mode 100644 Minecraft.Client/Common/UI/UIControl_BitmapIcon.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_BitmapIcon.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Button.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Button.h create mode 100644 Minecraft.Client/Common/UI/UIControl_ButtonList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_ButtonList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_CheckBox.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_CheckBox.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Cursor.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Cursor.h create mode 100644 Minecraft.Client/Common/UI/UIControl_DLCList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_DLCList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_DynamicLabel.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_DynamicLabel.h create mode 100644 Minecraft.Client/Common/UI/UIControl_EnchantmentBook.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_EnchantmentBook.h create mode 100644 Minecraft.Client/Common/UI/UIControl_EnchantmentButton.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_EnchantmentButton.h create mode 100644 Minecraft.Client/Common/UI/UIControl_HTMLLabel.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_HTMLLabel.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Label.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Label.h create mode 100644 Minecraft.Client/Common/UI/UIControl_LeaderboardList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_LeaderboardList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_MinecraftPlayer.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_MinecraftPlayer.h create mode 100644 Minecraft.Client/Common/UI/UIControl_PlayerList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_PlayerList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_PlayerSkinPreview.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_PlayerSkinPreview.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Progress.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Progress.h create mode 100644 Minecraft.Client/Common/UI/UIControl_SaveList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_SaveList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Slider.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Slider.h create mode 100644 Minecraft.Client/Common/UI/UIControl_SlotList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_SlotList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_SpaceIndicatorBar.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_SpaceIndicatorBar.h create mode 100644 Minecraft.Client/Common/UI/UIControl_TextInput.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_TextInput.h create mode 100644 Minecraft.Client/Common/UI/UIControl_TexturePackList.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_TexturePackList.h create mode 100644 Minecraft.Client/Common/UI/UIControl_Touch.cpp create mode 100644 Minecraft.Client/Common/UI/UIControl_Touch.h create mode 100644 Minecraft.Client/Common/UI/UIController.cpp create mode 100644 Minecraft.Client/Common/UI/UIController.h create mode 100644 Minecraft.Client/Common/UI/UIEnums.h create mode 100644 Minecraft.Client/Common/UI/UIFontData.cpp create mode 100644 Minecraft.Client/Common/UI/UIFontData.h create mode 100644 Minecraft.Client/Common/UI/UIGroup.cpp create mode 100644 Minecraft.Client/Common/UI/UIGroup.h create mode 100644 Minecraft.Client/Common/UI/UILayer.cpp create mode 100644 Minecraft.Client/Common/UI/UILayer.h create mode 100644 Minecraft.Client/Common/UI/UIScene.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene.h create mode 100644 Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_AbstractContainerMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_AnvilMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_AnvilMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_BrewingStandMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_BrewingStandMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_ConnectingProgress.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_ConnectingProgress.h create mode 100644 Minecraft.Client/Common/UI/UIScene_ContainerMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_ContainerMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_ControlsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_ControlsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_CraftingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_CraftingMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_CreateWorldMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_CreativeMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_CreativeMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_Credits.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_Credits.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DLCMainMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DLCMainMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DLCOffersMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DLCOffersMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DeathMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DeathMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugCreateSchematic.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugOptions.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugOptions.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugOverlay.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugOverlay.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugSetCamera.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DebugSetCamera.h create mode 100644 Minecraft.Client/Common/UI/UIScene_DispenserMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_DispenserMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_EULA.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_EULA.h create mode 100644 Minecraft.Client/Common/UI/UIScene_EnchantingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_EnchantingMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_EndPoem.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_EndPoem.h create mode 100644 Minecraft.Client/Common/UI/UIScene_FullscreenProgress.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_FullscreenProgress.h create mode 100644 Minecraft.Client/Common/UI/UIScene_FurnaceMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_FurnaceMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_HUD.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_HUD.h create mode 100644 Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_HelpAndOptionsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_HowToPlay.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_HowToPlay.h create mode 100644 Minecraft.Client/Common/UI/UIScene_HowToPlayMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_HowToPlayMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_InGameHostOptionsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_InGameHostOptionsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_InGameInfoMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_InGameInfoMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_InGamePlayerOptionsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_InGamePlayerOptionsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_InGameSaveManagementMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_InGameSaveManagementMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_Intro.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_Intro.h create mode 100644 Minecraft.Client/Common/UI/UIScene_InventoryMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_InventoryMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_JoinMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_JoinMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_Keyboard.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_Keyboard.h create mode 100644 Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_LaunchMoreOptionsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_LeaderboardsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_LeaderboardsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_LoadMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_LoadMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_LoadOrJoinMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_MainMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_MainMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_MessageBox.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_MessageBox.h create mode 100644 Minecraft.Client/Common/UI/UIScene_PauseMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_PauseMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_QuadrantSignin.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_QuadrantSignin.h create mode 100644 Minecraft.Client/Common/UI/UIScene_ReinstallMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_ReinstallMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SaveMessage.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SaveMessage.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsAudioMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsAudioMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsControlMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsControlMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsGraphicsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsOptionsMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsOptionsMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SettingsUIMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SignEntryMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SignEntryMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_SkinSelectMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_SkinSelectMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_TeleportMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_TeleportMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_Timer.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_Timer.h create mode 100644 Minecraft.Client/Common/UI/UIScene_TradingMenu.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_TradingMenu.h create mode 100644 Minecraft.Client/Common/UI/UIScene_TrialExitUpsell.cpp create mode 100644 Minecraft.Client/Common/UI/UIScene_TrialExitUpsell.h create mode 100644 Minecraft.Client/Common/UI/UIStructs.h create mode 100644 Minecraft.Client/Common/UI/UITTFFont.cpp create mode 100644 Minecraft.Client/Common/UI/UITTFFont.h create mode 100644 Minecraft.Client/Common/XUI/SlotProgressControl.cpp create mode 100644 Minecraft.Client/Common/XUI/SlotProgressControl.h create mode 100644 Minecraft.Client/Common/XUI/XUI_BasePlayer.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_BasePlayer.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Chat.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Chat.h create mode 100644 Minecraft.Client/Common/XUI/XUI_ConnectingProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_ConnectingProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Control_ComboBox.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Control_ComboBox.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Controls.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_4JEdit.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_4JIcon.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_4JList.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_BrewProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_BubblesProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_BurnProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_CraftIngredientSlot.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantButton.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentBook.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_EnchantmentButtonText.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_FireProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_LoadingProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftPlayer.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSkinPreview.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MinecraftSlot.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_MobEffect.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_PassThroughList.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_PassthroughList.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_ProgressCtrlBase.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SliderWrapper.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItem.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemCtrlBase.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SlotItemListItem.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SlotList.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Ctrl_SplashPulser.h create mode 100644 Minecraft.Client/Common/XUI/XUI_CustomMessages.h create mode 100644 Minecraft.Client/Common/XUI/XUI_DLCOffers.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_DLCOffers.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Death.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Death.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Debug.h create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugItemEditor.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugItemEditor.h create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugOverlay.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugOverlay.h create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugSchematicCreator.h create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugSetCamera.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugSetCamera.h create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugTips.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_DebugTips.h create mode 100644 Minecraft.Client/Common/XUI/XUI_FullscreenProgress.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_FullscreenProgress.h create mode 100644 Minecraft.Client/Common/XUI/XUI_HUD.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_HUD.h create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpAndOptions.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpAndOptions.h create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpControls.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpControls.h create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpCredits.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpCredits.h create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_HelpHowToPlay.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Helper.h create mode 100644 Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_HowToPlayMenu.h create mode 100644 Minecraft.Client/Common/XUI/XUI_InGameHostOptions.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_InGameHostOptions.h create mode 100644 Minecraft.Client/Common/XUI/XUI_InGameInfo.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_InGameInfo.h create mode 100644 Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_InGamePlayerOptions.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Intro.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Intro.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Leaderboards.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Leaderboards.h create mode 100644 Minecraft.Client/Common/XUI/XUI_LoadSettings.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_LoadSettings.h create mode 100644 Minecraft.Client/Common/XUI/XUI_MainMenu.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_MainMenu.h create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameCreate.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameCreate.h create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameInfo.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameInfo.h create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameJoinLoad.h create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_MultiGameLaunchMoreOptions.h create mode 100644 Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_NewUpdateMessage.h create mode 100644 Minecraft.Client/Common/XUI/XUI_PartnernetPassword.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_PartnernetPassword.h create mode 100644 Minecraft.Client/Common/XUI/XUI_PauseMenu.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_PauseMenu.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Reinstall.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Reinstall.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SaveMessage.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SaveMessage.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_AbstractContainer.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Anvil.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Anvil.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Base.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Base.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_BrewingStand.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Container.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Container.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_CraftingPanel.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Enchant.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Enchant.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Furnace.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Furnace.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Inventory.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Inventory.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Inventory_Creative.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Trading.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Trading.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Trap.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Trap.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Win.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Scene_Win.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsAll.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsAll.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsAudio.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsAudio.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsControl.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsControl.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsGraphics.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsGraphics.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsOptions.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsOptions.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsUI.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SettingsUI.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SignEntry.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SignEntry.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SkinSelect.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SkinSelect.h create mode 100644 Minecraft.Client/Common/XUI/XUI_SocialPost.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_SocialPost.h create mode 100644 Minecraft.Client/Common/XUI/XUI_Teleport.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_Teleport.h create mode 100644 Minecraft.Client/Common/XUI/XUI_TextEntry.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_TextEntry.h create mode 100644 Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_TransferToXboxOne.h create mode 100644 Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_TrialExitUpsell.h create mode 100644 Minecraft.Client/Common/XUI/XUI_TutorialPopup.cpp create mode 100644 Minecraft.Client/Common/XUI/XUI_TutorialPopup.h create mode 100644 Minecraft.Client/Common/XUI/XUI_XZP_Icons.h create mode 100644 Minecraft.Client/Common/XUI/XUI_debug.cpp create mode 100644 Minecraft.Client/Common/xuiscene_base.h create mode 100644 Minecraft.Client/Common/zlib/adler32.c create mode 100644 Minecraft.Client/Common/zlib/compress.c create mode 100644 Minecraft.Client/Common/zlib/crc32.c create mode 100644 Minecraft.Client/Common/zlib/crc32.h create mode 100644 Minecraft.Client/Common/zlib/deflate.c create mode 100644 Minecraft.Client/Common/zlib/deflate.h create mode 100644 Minecraft.Client/Common/zlib/gzclose.c create mode 100644 Minecraft.Client/Common/zlib/gzguts.h create mode 100644 Minecraft.Client/Common/zlib/gzlib.c create mode 100644 Minecraft.Client/Common/zlib/gzread.c create mode 100644 Minecraft.Client/Common/zlib/gzwrite.c create mode 100644 Minecraft.Client/Common/zlib/infback.c create mode 100644 Minecraft.Client/Common/zlib/inffast.c create mode 100644 Minecraft.Client/Common/zlib/inffast.h create mode 100644 Minecraft.Client/Common/zlib/inffixed.h create mode 100644 Minecraft.Client/Common/zlib/inflate.c create mode 100644 Minecraft.Client/Common/zlib/inflate.h create mode 100644 Minecraft.Client/Common/zlib/inftrees.c create mode 100644 Minecraft.Client/Common/zlib/inftrees.h create mode 100644 Minecraft.Client/Common/zlib/trees.c create mode 100644 Minecraft.Client/Common/zlib/trees.h create mode 100644 Minecraft.Client/Common/zlib/uncompr.c create mode 100644 Minecraft.Client/Common/zlib/zconf.h create mode 100644 Minecraft.Client/Common/zlib/zlib.h create mode 100644 Minecraft.Client/Common/zlib/zutil.c create mode 100644 Minecraft.Client/Common/zlib/zutil.h create mode 100644 Minecraft.Client/CompassTexture.cpp create mode 100644 Minecraft.Client/CompassTexture.h create mode 100644 Minecraft.Client/ConfirmScreen.cpp create mode 100644 Minecraft.Client/ConfirmScreen.h create mode 100644 Minecraft.Client/ConnectScreen.cpp create mode 100644 Minecraft.Client/ConnectScreen.h create mode 100644 Minecraft.Client/ConsoleInput.cpp create mode 100644 Minecraft.Client/ConsoleInput.h create mode 100644 Minecraft.Client/ConsoleInputSource.h create mode 100644 Minecraft.Client/ContainerScreen.cpp create mode 100644 Minecraft.Client/ContainerScreen.h create mode 100644 Minecraft.Client/ControlsScreen.cpp create mode 100644 Minecraft.Client/ControlsScreen.h create mode 100644 Minecraft.Client/CowModel.cpp create mode 100644 Minecraft.Client/CowModel.h create mode 100644 Minecraft.Client/CowRenderer.cpp create mode 100644 Minecraft.Client/CowRenderer.h create mode 100644 Minecraft.Client/CraftingScreen.cpp create mode 100644 Minecraft.Client/CraftingScreen.h create mode 100644 Minecraft.Client/CreateWorldScreen.cpp create mode 100644 Minecraft.Client/CreateWorldScreen.h create mode 100644 Minecraft.Client/CreativeMode.cpp create mode 100644 Minecraft.Client/CreativeMode.h create mode 100644 Minecraft.Client/CreeperModel.cpp create mode 100644 Minecraft.Client/CreeperModel.h create mode 100644 Minecraft.Client/CreeperRenderer.cpp create mode 100644 Minecraft.Client/CreeperRenderer.h create mode 100644 Minecraft.Client/CritParticle.cpp create mode 100644 Minecraft.Client/CritParticle.h create mode 100644 Minecraft.Client/CritParticle2.cpp create mode 100644 Minecraft.Client/CritParticle2.h create mode 100644 Minecraft.Client/Cube.cpp create mode 100644 Minecraft.Client/Cube.h create mode 100644 Minecraft.Client/Culler.h create mode 100644 Minecraft.Client/DLCTexturePack.cpp create mode 100644 Minecraft.Client/DLCTexturePack.h create mode 100644 Minecraft.Client/DeathScreen.cpp create mode 100644 Minecraft.Client/DeathScreen.h create mode 100644 Minecraft.Client/DefaultRenderer.cpp create mode 100644 Minecraft.Client/DefaultRenderer.h create mode 100644 Minecraft.Client/DefaultTexturePack.cpp create mode 100644 Minecraft.Client/DefaultTexturePack.h create mode 100644 Minecraft.Client/DemoLevel.cpp create mode 100644 Minecraft.Client/DemoLevel.h create mode 100644 Minecraft.Client/DemoMode.cpp create mode 100644 Minecraft.Client/DemoMode.h create mode 100644 Minecraft.Client/DemoUser.cpp create mode 100644 Minecraft.Client/DemoUser.h create mode 100644 Minecraft.Client/DerivedServerLevel.cpp create mode 100644 Minecraft.Client/DerivedServerLevel.h create mode 100644 Minecraft.Client/DirtyChunkSorter.cpp create mode 100644 Minecraft.Client/DirtyChunkSorter.h create mode 100644 Minecraft.Client/DisconnectedScreen.cpp create mode 100644 Minecraft.Client/DisconnectedScreen.h create mode 100644 Minecraft.Client/DistanceChunkSorter.cpp create mode 100644 Minecraft.Client/DistanceChunkSorter.h create mode 100644 Minecraft.Client/DragonBreathParticle.cpp create mode 100644 Minecraft.Client/DragonBreathParticle.h create mode 100644 Minecraft.Client/DragonModel.cpp create mode 100644 Minecraft.Client/DragonModel.h create mode 100644 Minecraft.Client/DripParticle.cpp create mode 100644 Minecraft.Client/DripParticle.h create mode 100644 Minecraft.Client/Durango/Achievements/AchievementManager.cpp create mode 100644 Minecraft.Client/Durango/Achievements/AchievementManager.h create mode 100644 Minecraft.Client/Durango/ApplicationView.cpp create mode 100644 Minecraft.Client/Durango/ApplicationView.h create mode 100644 Minecraft.Client/Durango/Autogenerated.appxmanifest create mode 100644 Minecraft.Client/Durango/DurangoExtras/DurangoStubs.cpp create mode 100644 Minecraft.Client/Durango/DurangoExtras/DurangoStubs.h create mode 100644 Minecraft.Client/Durango/DurangoExtras/xcompress.h create mode 100644 Minecraft.Client/Durango/Durango_App.cpp create mode 100644 Minecraft.Client/Durango/Durango_App.h create mode 100644 Minecraft.Client/Durango/Durango_Minecraft.cpp create mode 100644 Minecraft.Client/Durango/Durango_UIController.cpp create mode 100644 Minecraft.Client/Durango/Durango_UIController.h create mode 100644 Minecraft.Client/Durango/Leaderboards/DurangoLeaderboardManager.cpp create mode 100644 Minecraft.Client/Durango/Leaderboards/DurangoLeaderboardManager.h create mode 100644 Minecraft.Client/Durango/Leaderboards/DurangoStatsDebugger.cpp create mode 100644 Minecraft.Client/Durango/Leaderboards/DurangoStatsDebugger.h create mode 100644 Minecraft.Client/Durango/Leaderboards/GameProgress.cpp create mode 100644 Minecraft.Client/Durango/Leaderboards/GameProgress.h create mode 100644 Minecraft.Client/Durango/Minecraft_Macros.h create mode 100644 Minecraft.Client/Durango/Network/ChatIntegrationLayer.cpp create mode 100644 Minecraft.Client/Durango/Network/ChatIntegrationLayer.h create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkManager.cpp create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkManager.h create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkManager_FriendSessions.cpp create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkManager_Log.cpp create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkManager_SendReceive.cpp create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkManager_XRNSEvent.cpp create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkPlayer.cpp create mode 100644 Minecraft.Client/Durango/Network/DQRNetworkPlayer.h create mode 100644 Minecraft.Client/Durango/Network/NetworkPlayerDurango.cpp create mode 100644 Minecraft.Client/Durango/Network/NetworkPlayerDurango.h create mode 100644 Minecraft.Client/Durango/Network/PartyController.cpp create mode 100644 Minecraft.Client/Durango/Network/PartyController.h create mode 100644 Minecraft.Client/Durango/Network/PlatformNetworkManagerDurango.cpp create mode 100644 Minecraft.Client/Durango/Network/PlatformNetworkManagerDurango.h create mode 100644 Minecraft.Client/Durango/Network/base64.cpp create mode 100644 Minecraft.Client/Durango/Network/base64.h create mode 100644 Minecraft.Client/Durango/PresenceIds.h create mode 100644 Minecraft.Client/Durango/Resource.h create mode 100644 Minecraft.Client/Durango/ServiceConfig/Events-XBLA.8-149E11AEEvents.h create mode 100644 Minecraft.Client/Durango/ServiceConfig/HelpDocument/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/HelpDocument/main.css create mode 100644 Minecraft.Client/Durango/ServiceConfig/HelpDocument/mobile.css create mode 100644 Minecraft.Client/Durango/ServiceConfig/HelpDocument/skin.css create mode 100644 Minecraft.Client/Durango/ServiceConfig/HelpDocument/snapped.css create mode 100644 Minecraft.Client/Durango/ServiceConfig/HelpDocument/tablet.css create mode 100644 Minecraft.Client/Durango/ServiceConfig/MakeZips.py create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/de-DE/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/en-GB/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/es-ES/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/fr-FR/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/it-IT/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/ja-JP/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/ko-KR/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/pt-BR/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/pt-PT/index.html create mode 100644 Minecraft.Client/Durango/ServiceConfig/loc/zh-CHT/index.html create mode 100644 Minecraft.Client/Durango/Social/SocialManager.h create mode 100644 Minecraft.Client/Durango/XML/ATGXmlParser.cpp create mode 100644 Minecraft.Client/Durango/XML/ATGXmlParser.h create mode 100644 Minecraft.Client/Durango/XML/xmlFilesCallback.h create mode 100644 Minecraft.Client/Durango/XboxGameMode.cpp create mode 100644 Minecraft.Client/Durango/XboxGameMode.h create mode 100644 Minecraft.Client/Durango/Xbox_Awards_enum.h create mode 100644 Minecraft.Client/Durango/Xbox_BuildVer.h create mode 100644 Minecraft.Client/Durango/Xbox_Debug_enum.h create mode 100644 Minecraft.Client/Durango/Xbox_Utils.cpp create mode 100644 Minecraft.Client/Durango/manifest.xml create mode 100644 Minecraft.Client/Durango/targetver.h create mode 100644 Minecraft.Client/EchantmentTableParticle.cpp create mode 100644 Minecraft.Client/EchantmentTableParticle.h create mode 100644 Minecraft.Client/EditBox.cpp create mode 100644 Minecraft.Client/EditBox.h create mode 100644 Minecraft.Client/EnchantTableRenderer.cpp create mode 100644 Minecraft.Client/EnchantTableRenderer.h create mode 100644 Minecraft.Client/EnderChestRenderer.cpp create mode 100644 Minecraft.Client/EnderChestRenderer.h create mode 100644 Minecraft.Client/EnderCrystalModel.cpp create mode 100644 Minecraft.Client/EnderCrystalModel.h create mode 100644 Minecraft.Client/EnderCrystalRenderer.cpp create mode 100644 Minecraft.Client/EnderCrystalRenderer.h create mode 100644 Minecraft.Client/EnderDragonRenderer.cpp create mode 100644 Minecraft.Client/EnderDragonRenderer.h create mode 100644 Minecraft.Client/EnderParticle.cpp create mode 100644 Minecraft.Client/EnderParticle.h create mode 100644 Minecraft.Client/EndermanModel.cpp create mode 100644 Minecraft.Client/EndermanModel.h create mode 100644 Minecraft.Client/EndermanRenderer.cpp create mode 100644 Minecraft.Client/EndermanRenderer.h create mode 100644 Minecraft.Client/EntityRenderDispatcher.cpp create mode 100644 Minecraft.Client/EntityRenderDispatcher.h create mode 100644 Minecraft.Client/EntityRenderer.cpp create mode 100644 Minecraft.Client/EntityRenderer.h create mode 100644 Minecraft.Client/EntityTileRenderer.cpp create mode 100644 Minecraft.Client/EntityTileRenderer.h create mode 100644 Minecraft.Client/EntityTracker.cpp create mode 100644 Minecraft.Client/EntityTracker.h create mode 100644 Minecraft.Client/ErrorScreen.cpp create mode 100644 Minecraft.Client/ErrorScreen.h create mode 100644 Minecraft.Client/ExperienceOrbRenderer.cpp create mode 100644 Minecraft.Client/ExperienceOrbRenderer.h create mode 100644 Minecraft.Client/ExplodeParticle.cpp create mode 100644 Minecraft.Client/ExplodeParticle.h create mode 100644 Minecraft.Client/Extrax64Stubs.cpp create mode 100644 Minecraft.Client/FallingTileRenderer.cpp create mode 100644 Minecraft.Client/FallingTileRenderer.h create mode 100644 Minecraft.Client/FileTexturePack.cpp create mode 100644 Minecraft.Client/FileTexturePack.h create mode 100644 Minecraft.Client/FireballRenderer.cpp create mode 100644 Minecraft.Client/FireballRenderer.h create mode 100644 Minecraft.Client/FishingHookRenderer.cpp create mode 100644 Minecraft.Client/FishingHookRenderer.h create mode 100644 Minecraft.Client/FlameParticle.cpp create mode 100644 Minecraft.Client/FlameParticle.h create mode 100644 Minecraft.Client/FolderTexturePack.cpp create mode 100644 Minecraft.Client/FolderTexturePack.h create mode 100644 Minecraft.Client/Font.cpp create mode 100644 Minecraft.Client/Font.h create mode 100644 Minecraft.Client/FootstepParticle.cpp create mode 100644 Minecraft.Client/FootstepParticle.h create mode 100644 Minecraft.Client/Frustum.cpp create mode 100644 Minecraft.Client/Frustum.h create mode 100644 Minecraft.Client/FrustumCuller.cpp create mode 100644 Minecraft.Client/FrustumCuller.h create mode 100644 Minecraft.Client/FrustumData.cpp create mode 100644 Minecraft.Client/FrustumData.h create mode 100644 Minecraft.Client/FurnaceScreen.cpp create mode 100644 Minecraft.Client/FurnaceScreen.h create mode 100644 Minecraft.Client/GameMode.cpp create mode 100644 Minecraft.Client/GameMode.h create mode 100644 Minecraft.Client/GameRenderer.cpp create mode 100644 Minecraft.Client/GameRenderer.h create mode 100644 Minecraft.Client/GhastModel.cpp create mode 100644 Minecraft.Client/GhastModel.h create mode 100644 Minecraft.Client/GhastRenderer.cpp create mode 100644 Minecraft.Client/GhastRenderer.h create mode 100644 Minecraft.Client/GiantMobRenderer.cpp create mode 100644 Minecraft.Client/GiantMobRenderer.h create mode 100644 Minecraft.Client/Gui.cpp create mode 100644 Minecraft.Client/Gui.h create mode 100644 Minecraft.Client/GuiComponent.cpp create mode 100644 Minecraft.Client/GuiComponent.h create mode 100644 Minecraft.Client/GuiMessage.cpp create mode 100644 Minecraft.Client/GuiMessage.h create mode 100644 Minecraft.Client/GuiParticle.cpp create mode 100644 Minecraft.Client/GuiParticle.h create mode 100644 Minecraft.Client/GuiParticles.cpp create mode 100644 Minecraft.Client/GuiParticles.h create mode 100644 Minecraft.Client/HeartParticle.cpp create mode 100644 Minecraft.Client/HeartParticle.h create mode 100644 Minecraft.Client/HttpTexture.cpp create mode 100644 Minecraft.Client/HttpTexture.h create mode 100644 Minecraft.Client/HttpTextureProcessor.h create mode 100644 Minecraft.Client/HugeExplosionParticle.cpp create mode 100644 Minecraft.Client/HugeExplosionParticle.h create mode 100644 Minecraft.Client/HugeExplosionSeedParticle.cpp create mode 100644 Minecraft.Client/HugeExplosionSeedParticle.h create mode 100644 Minecraft.Client/HumanoidMobRenderer.cpp create mode 100644 Minecraft.Client/HumanoidMobRenderer.h create mode 100644 Minecraft.Client/HumanoidModel.cpp create mode 100644 Minecraft.Client/HumanoidModel.h create mode 100644 Minecraft.Client/InBedChatScreen.cpp create mode 100644 Minecraft.Client/InBedChatScreen.h create mode 100644 Minecraft.Client/Input.cpp create mode 100644 Minecraft.Client/Input.h create mode 100644 Minecraft.Client/InventoryScreen.cpp create mode 100644 Minecraft.Client/InventoryScreen.h create mode 100644 Minecraft.Client/ItemFrameRenderer.cpp create mode 100644 Minecraft.Client/ItemFrameRenderer.h create mode 100644 Minecraft.Client/ItemInHandRenderer.cpp create mode 100644 Minecraft.Client/ItemInHandRenderer.h create mode 100644 Minecraft.Client/ItemRenderer.cpp create mode 100644 Minecraft.Client/ItemRenderer.h create mode 100644 Minecraft.Client/ItemSpriteRenderer.cpp create mode 100644 Minecraft.Client/ItemSpriteRenderer.h create mode 100644 Minecraft.Client/JoinMultiplayerScreen.cpp create mode 100644 Minecraft.Client/JoinMultiplayerScreen.h create mode 100644 Minecraft.Client/KeyMapping.cpp create mode 100644 Minecraft.Client/KeyMapping.h create mode 100644 Minecraft.Client/KeyboardMouseInput.cpp create mode 100644 Minecraft.Client/KeyboardMouseInput.h create mode 100644 Minecraft.Client/LargeChestModel.cpp create mode 100644 Minecraft.Client/LargeChestModel.h create mode 100644 Minecraft.Client/LavaParticle.cpp create mode 100644 Minecraft.Client/LavaParticle.h create mode 100644 Minecraft.Client/LavaSlimeModel.cpp create mode 100644 Minecraft.Client/LavaSlimeModel.h create mode 100644 Minecraft.Client/LavaSlimeRenderer.cpp create mode 100644 Minecraft.Client/LavaSlimeRenderer.h create mode 100644 Minecraft.Client/LevelRenderer.cpp create mode 100644 Minecraft.Client/LevelRenderer.h create mode 100644 Minecraft.Client/Lighting.cpp create mode 100644 Minecraft.Client/Lighting.h create mode 100644 Minecraft.Client/LightningBoltRenderer.cpp create mode 100644 Minecraft.Client/LightningBoltRenderer.h create mode 100644 Minecraft.Client/LocalPlayer.cpp create mode 100644 Minecraft.Client/LocalPlayer.h create mode 100644 Minecraft.Client/MemTexture.cpp create mode 100644 Minecraft.Client/MemTexture.h create mode 100644 Minecraft.Client/MemTextureProcessor.h create mode 100644 Minecraft.Client/MemoryTracker.cpp create mode 100644 Minecraft.Client/MemoryTracker.h create mode 100644 Minecraft.Client/MinecartModel.cpp create mode 100644 Minecraft.Client/MinecartModel.h create mode 100644 Minecraft.Client/MinecartRenderer.cpp create mode 100644 Minecraft.Client/MinecartRenderer.h create mode 100644 Minecraft.Client/Minecraft.Client.vcxproj create mode 100644 Minecraft.Client/Minecraft.Client.vcxproj.filters create mode 100644 Minecraft.Client/Minecraft.cpp create mode 100644 Minecraft.Client/Minecraft.h create mode 100644 Minecraft.Client/MinecraftServer.cpp create mode 100644 Minecraft.Client/MinecraftServer.h create mode 100644 Minecraft.Client/Minimap.cpp create mode 100644 Minecraft.Client/Minimap.h create mode 100644 Minecraft.Client/MobRenderer.cpp create mode 100644 Minecraft.Client/MobRenderer.h create mode 100644 Minecraft.Client/MobSkinMemTextureProcessor.cpp create mode 100644 Minecraft.Client/MobSkinMemTextureProcessor.h create mode 100644 Minecraft.Client/MobSkinTextureProcessor.cpp create mode 100644 Minecraft.Client/MobSkinTextureProcessor.h create mode 100644 Minecraft.Client/MobSpawnerRenderer.cpp create mode 100644 Minecraft.Client/MobSpawnerRenderer.h create mode 100644 Minecraft.Client/Model.cpp create mode 100644 Minecraft.Client/Model.h create mode 100644 Minecraft.Client/ModelPart.cpp create mode 100644 Minecraft.Client/ModelPart.h create mode 100644 Minecraft.Client/MultiPlayerChunkCache.cpp create mode 100644 Minecraft.Client/MultiPlayerChunkCache.h create mode 100644 Minecraft.Client/MultiPlayerGameMode.cpp create mode 100644 Minecraft.Client/MultiPlayerGameMode.h create mode 100644 Minecraft.Client/MultiPlayerLevel.cpp create mode 100644 Minecraft.Client/MultiPlayerLevel.h create mode 100644 Minecraft.Client/MultiPlayerLocalPlayer.cpp create mode 100644 Minecraft.Client/MultiPlayerLocalPlayer.h create mode 100644 Minecraft.Client/MushroomCowRenderer.cpp create mode 100644 Minecraft.Client/MushroomCowRenderer.h create mode 100644 Minecraft.Client/NameEntryScreen.cpp create mode 100644 Minecraft.Client/NameEntryScreen.h create mode 100644 Minecraft.Client/NetherPortalParticle.cpp create mode 100644 Minecraft.Client/NetherPortalParticle.h create mode 100644 Minecraft.Client/Network Implementation Notes.txt create mode 100644 Minecraft.Client/NoteParticle.cpp create mode 100644 Minecraft.Client/NoteParticle.h create mode 100644 Minecraft.Client/OffsettedRenderList.cpp create mode 100644 Minecraft.Client/OffsettedRenderList.h create mode 100644 Minecraft.Client/Options.cpp create mode 100644 Minecraft.Client/Options.h create mode 100644 Minecraft.Client/OptionsScreen.cpp create mode 100644 Minecraft.Client/OptionsScreen.h create mode 100644 Minecraft.Client/Orbis/Assert/assert.h create mode 100644 Minecraft.Client/Orbis/Leaderboards/OrbisLeaderboardManager.cpp create mode 100644 Minecraft.Client/Orbis/Leaderboards/OrbisLeaderboardManager.h create mode 100644 Minecraft.Client/Orbis/Leaderboards/base64.cpp create mode 100644 Minecraft.Client/Orbis/Leaderboards/base64.h create mode 100644 Minecraft.Client/Orbis/MinecraftPronunciation/MinecraftPronunciation.xml create mode 100644 Minecraft.Client/Orbis/MinecraftPronunciation/pronunciation.xml create mode 100644 Minecraft.Client/Orbis/Minecraft_Macros.h create mode 100644 Minecraft.Client/Orbis/Network/Orbis_NPToolkit.cpp create mode 100644 Minecraft.Client/Orbis/Network/Orbis_NPToolkit.h create mode 100644 Minecraft.Client/Orbis/Network/PsPlusUpsellWrapper_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/PsPlusUpsellWrapper_Orbis.h create mode 100644 Minecraft.Client/Orbis/Network/SQRNetworkManager_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/SQRNetworkManager_Orbis.h create mode 100644 Minecraft.Client/Orbis/Network/SonyCommerce_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/SonyCommerce_Orbis.h create mode 100644 Minecraft.Client/Orbis/Network/SonyHttp_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/SonyHttp_Orbis.h create mode 100644 Minecraft.Client/Orbis/Network/SonyRemoteStorage_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/SonyRemoteStorage_Orbis.h create mode 100644 Minecraft.Client/Orbis/Network/SonyVoiceChatParty_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/SonyVoiceChatParty_Orbis.h create mode 100644 Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.cpp create mode 100644 Minecraft.Client/Orbis/Network/SonyVoiceChat_Orbis.h create mode 100644 Minecraft.Client/Orbis/OrbisExtras/OrbisMaths.h create mode 100644 Minecraft.Client/Orbis/OrbisExtras/OrbisStubs.cpp create mode 100644 Minecraft.Client/Orbis/OrbisExtras/OrbisStubs.h create mode 100644 Minecraft.Client/Orbis/OrbisExtras/OrbisTypes.h create mode 100644 Minecraft.Client/Orbis/OrbisExtras/ShutdownManager.h create mode 100644 Minecraft.Client/Orbis/OrbisExtras/TLSStorage.cpp create mode 100644 Minecraft.Client/Orbis/OrbisExtras/TLSStorage.h create mode 100644 Minecraft.Client/Orbis/OrbisExtras/winerror.h create mode 100644 Minecraft.Client/Orbis/Orbis_App.cpp create mode 100644 Minecraft.Client/Orbis/Orbis_App.h create mode 100644 Minecraft.Client/Orbis/Orbis_Minecraft.cpp create mode 100644 Minecraft.Client/Orbis/Orbis_PlayerUID.cpp create mode 100644 Minecraft.Client/Orbis/Orbis_PlayerUID.h create mode 100644 Minecraft.Client/Orbis/Orbis_UIController.cpp create mode 100644 Minecraft.Client/Orbis/Orbis_UIController.h create mode 100644 Minecraft.Client/Orbis/Social/SocialManager.h create mode 100644 Minecraft.Client/Orbis/XML/ATGXmlParser.h create mode 100644 Minecraft.Client/Orbis/Xbox_BuildVer.h create mode 100644 Minecraft.Client/Orbis/min/min.xml create mode 100644 Minecraft.Client/Orbis/min/pronunciation.xml create mode 100644 Minecraft.Client/Orbis/ps4__np_conf.h create mode 100644 Minecraft.Client/Orbis/user_malloc.cpp create mode 100644 Minecraft.Client/Orbis/user_malloc_for_tls.cpp create mode 100644 Minecraft.Client/Orbis/user_new.cpp create mode 100644 Minecraft.Client/OzelotModel.cpp create mode 100644 Minecraft.Client/OzelotModel.h create mode 100644 Minecraft.Client/OzelotRenderer.cpp create mode 100644 Minecraft.Client/OzelotRenderer.h create mode 100644 Minecraft.Client/PS3/Assert/assert.h create mode 100644 Minecraft.Client/PS3/Audio/PS3_SoundEngine.cpp create mode 100644 Minecraft.Client/PS3/GameConfig/Minecraft.spa.h create mode 100644 Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.cpp create mode 100644 Minecraft.Client/PS3/Leaderboards/PS3LeaderboardManager.h create mode 100644 Minecraft.Client/PS3/Leaderboards/base64.cpp create mode 100644 Minecraft.Client/PS3/Leaderboards/base64.h create mode 100644 Minecraft.Client/PS3/Minecraft_Macros.h create mode 100644 Minecraft.Client/PS3/Network/SQRNetworkManager_PS3.cpp create mode 100644 Minecraft.Client/PS3/Network/SQRNetworkManager_PS3.h create mode 100644 Minecraft.Client/PS3/Network/SonyCommerce_PS3.cpp create mode 100644 Minecraft.Client/PS3/Network/SonyCommerce_PS3.h create mode 100644 Minecraft.Client/PS3/Network/SonyHttp_PS3.cpp create mode 100644 Minecraft.Client/PS3/Network/SonyHttp_PS3.h create mode 100644 Minecraft.Client/PS3/Network/SonyRemoteStorage_PS3.cpp create mode 100644 Minecraft.Client/PS3/Network/SonyRemoteStorage_PS3.h create mode 100644 Minecraft.Client/PS3/Network/SonyVoiceChat.cpp create mode 100644 Minecraft.Client/PS3/Network/SonyVoiceChat.h create mode 100644 Minecraft.Client/PS3/PS3Extras/C4JSpursJob.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/C4JSpursJob.h create mode 100644 Minecraft.Client/PS3/PS3Extras/C4JThread_SPU.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/C4JThread_SPU.h create mode 100644 Minecraft.Client/PS3/PS3Extras/EdgeZLib.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/EdgeZLib.h create mode 100644 Minecraft.Client/PS3/PS3Extras/PS3Maths.h create mode 100644 Minecraft.Client/PS3/PS3Extras/PS3Strings.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/PS3Strings.h create mode 100644 Minecraft.Client/PS3/PS3Extras/Ps3Stubs.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/Ps3Stubs.h create mode 100644 Minecraft.Client/PS3/PS3Extras/Ps3Types.h create mode 100644 Minecraft.Client/PS3/PS3Extras/ShutdownManager.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/ShutdownManager.h create mode 100644 Minecraft.Client/PS3/PS3Extras/TLSStorage.cpp create mode 100644 Minecraft.Client/PS3/PS3Extras/TLSStorage.h create mode 100644 Minecraft.Client/PS3/PS3Extras/winerror.h create mode 100644 Minecraft.Client/PS3/PS3_App.cpp create mode 100644 Minecraft.Client/PS3/PS3_App.h create mode 100644 Minecraft.Client/PS3/PS3_Minecraft.cpp create mode 100644 Minecraft.Client/PS3/PS3_PlayerUID.cpp create mode 100644 Minecraft.Client/PS3/PS3_PlayerUID.h create mode 100644 Minecraft.Client/PS3/PS3_UIController.cpp create mode 100644 Minecraft.Client/PS3/PS3_UIController.h create mode 100644 Minecraft.Client/PS3/Resource.h create mode 100644 Minecraft.Client/PS3/Social/SocialManager.h create mode 100644 Minecraft.Client/PS3/XML/ATGXmlParser.h create mode 100644 Minecraft.Client/PS3/XML/xmlFilesCallback.h create mode 100644 Minecraft.Client/PS3/XboxGameMode.cpp create mode 100644 Minecraft.Client/PS3/XboxGameMode.h create mode 100644 Minecraft.Client/PS3/Xbox_Awards_enum.h create mode 100644 Minecraft.Client/PS3/Xbox_BuildVer.h create mode 100644 Minecraft.Client/PS3/Xbox_Debug_enum.h create mode 100644 Minecraft.Client/PS3/Xbox_Minecraft.cpp create mode 100644 Minecraft.Client/PS3/Xbox_Utils.cpp create mode 100644 Minecraft.Client/PS3/targetver.h create mode 100644 Minecraft.Client/PSVita/Assert/assert.h create mode 100644 Minecraft.Client/PSVita/GameConfig/Minecraft.spa.h create mode 100644 Minecraft.Client/PSVita/GameConfig/rename.py create mode 100644 Minecraft.Client/PSVita/Leaderboards/PSVitaLeaderboardManager.cpp create mode 100644 Minecraft.Client/PSVita/Leaderboards/PSVitaLeaderboardManager.h create mode 100644 Minecraft.Client/PSVita/Leaderboards/base64.cpp create mode 100644 Minecraft.Client/PSVita/Leaderboards/base64.h create mode 100644 Minecraft.Client/PSVita/Network/PSVita_NPToolkit.cpp create mode 100644 Minecraft.Client/PSVita/Network/PSVita_NPToolkit.h create mode 100644 Minecraft.Client/PSVita/Network/SQRNetworkManager_AdHoc_Vita.cpp create mode 100644 Minecraft.Client/PSVita/Network/SQRNetworkManager_AdHoc_Vita.h create mode 100644 Minecraft.Client/PSVita/Network/SQRNetworkManager_Vita.cpp create mode 100644 Minecraft.Client/PSVita/Network/SQRNetworkManager_Vita.h create mode 100644 Minecraft.Client/PSVita/Network/SonyCommerce_Vita.cpp create mode 100644 Minecraft.Client/PSVita/Network/SonyCommerce_Vita.h create mode 100644 Minecraft.Client/PSVita/Network/SonyHttp_Vita.cpp create mode 100644 Minecraft.Client/PSVita/Network/SonyHttp_Vita.h create mode 100644 Minecraft.Client/PSVita/Network/SonyRemoteStorage_Vita.cpp create mode 100644 Minecraft.Client/PSVita/Network/SonyRemoteStorage_Vita.h create mode 100644 Minecraft.Client/PSVita/Network/SonyVoiceChat_Vita.cpp create mode 100644 Minecraft.Client/PSVita/Network/SonyVoiceChat_Vita.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/Conf.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/CustomMap.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/CustomMap.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/CustomSet.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/CustomSet.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaMaths.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaStrings.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaStrings.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaStubs.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaTLSStorage.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaTLSStorage.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PSVitaTypes.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/PsVitaStubs.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/ShutdownManager.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/ShutdownManager.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/TLSStorage.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/TLSStorage.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/libdivide.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/user_malloc.c create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/user_malloc_for_tls.c create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/user_new.cpp create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/zconf.h create mode 100644 Minecraft.Client/PSVita/PSVitaExtras/zlib.h create mode 100644 Minecraft.Client/PSVita/PSVita_App.cpp create mode 100644 Minecraft.Client/PSVita/PSVita_App.h create mode 100644 Minecraft.Client/PSVita/PSVita_Minecraft.cpp create mode 100644 Minecraft.Client/PSVita/PSVita_PlayerUID.cpp create mode 100644 Minecraft.Client/PSVita/PSVita_PlayerUID.h create mode 100644 Minecraft.Client/PSVita/PSVita_UIController.cpp create mode 100644 Minecraft.Client/PSVita/PSVita_UIController.h create mode 100644 Minecraft.Client/PSVita/Social/SocialManager.h create mode 100644 Minecraft.Client/PSVita/XML/ATGXmlParser.h create mode 100644 Minecraft.Client/PSVita/configuration.psp2path create mode 100644 Minecraft.Client/PaintingRenderer.cpp create mode 100644 Minecraft.Client/PaintingRenderer.h create mode 100644 Minecraft.Client/Particle.cpp create mode 100644 Minecraft.Client/Particle.h create mode 100644 Minecraft.Client/ParticleEngine.cpp create mode 100644 Minecraft.Client/ParticleEngine.h create mode 100644 Minecraft.Client/PauseScreen.cpp create mode 100644 Minecraft.Client/PauseScreen.h create mode 100644 Minecraft.Client/PendingConnection.cpp create mode 100644 Minecraft.Client/PendingConnection.h create mode 100644 Minecraft.Client/PigModel.cpp create mode 100644 Minecraft.Client/PigModel.h create mode 100644 Minecraft.Client/PigRenderer.cpp create mode 100644 Minecraft.Client/PigRenderer.h create mode 100644 Minecraft.Client/PistonPieceRenderer.cpp create mode 100644 Minecraft.Client/PistonPieceRenderer.h create mode 100644 Minecraft.Client/PlayerChunkMap.cpp create mode 100644 Minecraft.Client/PlayerChunkMap.h create mode 100644 Minecraft.Client/PlayerCloudParticle.cpp create mode 100644 Minecraft.Client/PlayerCloudParticle.h create mode 100644 Minecraft.Client/PlayerConnection.cpp create mode 100644 Minecraft.Client/PlayerConnection.h create mode 100644 Minecraft.Client/PlayerInfo.h create mode 100644 Minecraft.Client/PlayerList.cpp create mode 100644 Minecraft.Client/PlayerList.h create mode 100644 Minecraft.Client/PlayerRenderer.cpp create mode 100644 Minecraft.Client/PlayerRenderer.h create mode 100644 Minecraft.Client/Polygon.cpp create mode 100644 Minecraft.Client/Polygon.h create mode 100644 Minecraft.Client/PreStitchedTextureMap.cpp create mode 100644 Minecraft.Client/PreStitchedTextureMap.h create mode 100644 Minecraft.Client/ProgressRenderer.cpp create mode 100644 Minecraft.Client/ProgressRenderer.h create mode 100644 Minecraft.Client/QuadrupedModel.cpp create mode 100644 Minecraft.Client/QuadrupedModel.h create mode 100644 Minecraft.Client/ReadMe.txt create mode 100644 Minecraft.Client/ReceivingLevelScreen.cpp create mode 100644 Minecraft.Client/ReceivingLevelScreen.h create mode 100644 Minecraft.Client/Rect2i.cpp create mode 100644 Minecraft.Client/Rect2i.h create mode 100644 Minecraft.Client/RedDustParticle.cpp create mode 100644 Minecraft.Client/RedDustParticle.h create mode 100644 Minecraft.Client/RemotePlayer.cpp create mode 100644 Minecraft.Client/RemotePlayer.h create mode 100644 Minecraft.Client/RenameWorldScreen.cpp create mode 100644 Minecraft.Client/RenameWorldScreen.h create mode 100644 Minecraft.Client/Screen.cpp create mode 100644 Minecraft.Client/Screen.h create mode 100644 Minecraft.Client/ScreenSizeCalculator.cpp create mode 100644 Minecraft.Client/ScreenSizeCalculator.h create mode 100644 Minecraft.Client/ScrolledSelectionList.cpp create mode 100644 Minecraft.Client/ScrolledSelectionList.h create mode 100644 Minecraft.Client/SelectWorldScreen.cpp create mode 100644 Minecraft.Client/SelectWorldScreen.h create mode 100644 Minecraft.Client/ServerChunkCache.cpp create mode 100644 Minecraft.Client/ServerChunkCache.h create mode 100644 Minecraft.Client/ServerCommandDispatcher.cpp create mode 100644 Minecraft.Client/ServerCommandDispatcher.h create mode 100644 Minecraft.Client/ServerConnection.cpp create mode 100644 Minecraft.Client/ServerConnection.h create mode 100644 Minecraft.Client/ServerInterface.h create mode 100644 Minecraft.Client/ServerLevel.cpp create mode 100644 Minecraft.Client/ServerLevel.h create mode 100644 Minecraft.Client/ServerLevelListener.cpp create mode 100644 Minecraft.Client/ServerLevelListener.h create mode 100644 Minecraft.Client/ServerPlayer.cpp create mode 100644 Minecraft.Client/ServerPlayer.h create mode 100644 Minecraft.Client/ServerPlayerGameMode.cpp create mode 100644 Minecraft.Client/ServerPlayerGameMode.h create mode 100644 Minecraft.Client/Settings.cpp create mode 100644 Minecraft.Client/Settings.h create mode 100644 Minecraft.Client/SheepFurModel.cpp create mode 100644 Minecraft.Client/SheepFurModel.h create mode 100644 Minecraft.Client/SheepModel.cpp create mode 100644 Minecraft.Client/SheepModel.h create mode 100644 Minecraft.Client/SheepRenderer.cpp create mode 100644 Minecraft.Client/SheepRenderer.h create mode 100644 Minecraft.Client/SignModel.cpp create mode 100644 Minecraft.Client/SignModel.h create mode 100644 Minecraft.Client/SignRenderer.cpp create mode 100644 Minecraft.Client/SignRenderer.h create mode 100644 Minecraft.Client/SilverfishModel.cpp create mode 100644 Minecraft.Client/SilverfishModel.h create mode 100644 Minecraft.Client/SilverfishRenderer.cpp create mode 100644 Minecraft.Client/SilverfishRenderer.h create mode 100644 Minecraft.Client/SimpleIcon.cpp create mode 100644 Minecraft.Client/SimpleIcon.h create mode 100644 Minecraft.Client/SkeletonHeadModel.cpp create mode 100644 Minecraft.Client/SkeletonHeadModel.h create mode 100644 Minecraft.Client/SkeletonModel.cpp create mode 100644 Minecraft.Client/SkeletonModel.h create mode 100644 Minecraft.Client/SkinBox.h create mode 100644 Minecraft.Client/SkullTileRenderer.cpp create mode 100644 Minecraft.Client/SkullTileRenderer.h create mode 100644 Minecraft.Client/SlideButton.cpp create mode 100644 Minecraft.Client/SlideButton.h create mode 100644 Minecraft.Client/SlimeModel.cpp create mode 100644 Minecraft.Client/SlimeModel.h create mode 100644 Minecraft.Client/SlimeRenderer.cpp create mode 100644 Minecraft.Client/SlimeRenderer.h create mode 100644 Minecraft.Client/SmallButton.cpp create mode 100644 Minecraft.Client/SmallButton.h create mode 100644 Minecraft.Client/SmokeParticle.cpp create mode 100644 Minecraft.Client/SmokeParticle.h create mode 100644 Minecraft.Client/SnowManModel.cpp create mode 100644 Minecraft.Client/SnowManModel.h create mode 100644 Minecraft.Client/SnowManRenderer.cpp create mode 100644 Minecraft.Client/SnowManRenderer.h create mode 100644 Minecraft.Client/SnowShovelParticle.cpp create mode 100644 Minecraft.Client/SnowShovelParticle.h create mode 100644 Minecraft.Client/SpellParticle.cpp create mode 100644 Minecraft.Client/SpellParticle.h create mode 100644 Minecraft.Client/SpiderModel.cpp create mode 100644 Minecraft.Client/SpiderModel.h create mode 100644 Minecraft.Client/SpiderRenderer.cpp create mode 100644 Minecraft.Client/SpiderRenderer.h create mode 100644 Minecraft.Client/SplashParticle.cpp create mode 100644 Minecraft.Client/SplashParticle.h create mode 100644 Minecraft.Client/SquidModel.cpp create mode 100644 Minecraft.Client/SquidModel.h create mode 100644 Minecraft.Client/SquidRenderer.cpp create mode 100644 Minecraft.Client/SquidRenderer.h create mode 100644 Minecraft.Client/StatsCounter.cpp create mode 100644 Minecraft.Client/StatsCounter.h create mode 100644 Minecraft.Client/StatsScreen.cpp create mode 100644 Minecraft.Client/StatsScreen.h create mode 100644 Minecraft.Client/StatsSyncher.cpp create mode 100644 Minecraft.Client/StatsSyncher.h create mode 100644 Minecraft.Client/StitchSlot.cpp create mode 100644 Minecraft.Client/StitchSlot.h create mode 100644 Minecraft.Client/StitchedTexture.cpp create mode 100644 Minecraft.Client/StitchedTexture.h create mode 100644 Minecraft.Client/Stitcher.cpp create mode 100644 Minecraft.Client/Stitcher.h create mode 100644 Minecraft.Client/StringTable.cpp create mode 100644 Minecraft.Client/StringTable.h create mode 100644 Minecraft.Client/SurvivalMode.cpp create mode 100644 Minecraft.Client/SurvivalMode.h create mode 100644 Minecraft.Client/SuspendedParticle.cpp create mode 100644 Minecraft.Client/SuspendedParticle.h create mode 100644 Minecraft.Client/SuspendedTownParticle.cpp create mode 100644 Minecraft.Client/SuspendedTownParticle.h create mode 100644 Minecraft.Client/TakeAnimationParticle.cpp create mode 100644 Minecraft.Client/TakeAnimationParticle.h create mode 100644 Minecraft.Client/TeleportCommand.cpp create mode 100644 Minecraft.Client/TeleportCommand.h create mode 100644 Minecraft.Client/TerrainParticle.cpp create mode 100644 Minecraft.Client/TerrainParticle.h create mode 100644 Minecraft.Client/Tesselator.cpp create mode 100644 Minecraft.Client/Tesselator.h create mode 100644 Minecraft.Client/TexOffs.cpp create mode 100644 Minecraft.Client/TexOffs.h create mode 100644 Minecraft.Client/TextEditScreen.cpp create mode 100644 Minecraft.Client/TextEditScreen.h create mode 100644 Minecraft.Client/Texture.cpp create mode 100644 Minecraft.Client/Texture.h create mode 100644 Minecraft.Client/TextureHolder.cpp create mode 100644 Minecraft.Client/TextureHolder.h create mode 100644 Minecraft.Client/TextureManager.cpp create mode 100644 Minecraft.Client/TextureManager.h create mode 100644 Minecraft.Client/TextureMap.cpp create mode 100644 Minecraft.Client/TextureMap.h create mode 100644 Minecraft.Client/TexturePack.cpp create mode 100644 Minecraft.Client/TexturePack.h create mode 100644 Minecraft.Client/TexturePackRepository.cpp create mode 100644 Minecraft.Client/TexturePackRepository.h create mode 100644 Minecraft.Client/Textures.cpp create mode 100644 Minecraft.Client/Textures.h create mode 100644 Minecraft.Client/TheEndPortalRenderer.cpp create mode 100644 Minecraft.Client/TheEndPortalRenderer.h create mode 100644 Minecraft.Client/TileEntityRenderDispatcher.cpp create mode 100644 Minecraft.Client/TileEntityRenderDispatcher.h create mode 100644 Minecraft.Client/TileEntityRenderer.cpp create mode 100644 Minecraft.Client/TileEntityRenderer.h create mode 100644 Minecraft.Client/TileRenderer.cpp create mode 100644 Minecraft.Client/TileRenderer.h create mode 100644 Minecraft.Client/Timer.cpp create mode 100644 Minecraft.Client/Timer.h create mode 100644 Minecraft.Client/TitleScreen.cpp create mode 100644 Minecraft.Client/TitleScreen.h create mode 100644 Minecraft.Client/TntRenderer.cpp create mode 100644 Minecraft.Client/TntRenderer.h create mode 100644 Minecraft.Client/TrackedEntity.cpp create mode 100644 Minecraft.Client/TrackedEntity.h create mode 100644 Minecraft.Client/TrapScreen.cpp create mode 100644 Minecraft.Client/TrapScreen.h create mode 100644 Minecraft.Client/User.cpp create mode 100644 Minecraft.Client/User.h create mode 100644 Minecraft.Client/Vertex.cpp create mode 100644 Minecraft.Client/Vertex.h create mode 100644 Minecraft.Client/VideoSettingsScreen.cpp create mode 100644 Minecraft.Client/VideoSettingsScreen.h create mode 100644 Minecraft.Client/ViewportCuller.cpp create mode 100644 Minecraft.Client/ViewportCuller.h create mode 100644 Minecraft.Client/VillagerGolemModel.cpp create mode 100644 Minecraft.Client/VillagerGolemModel.h create mode 100644 Minecraft.Client/VillagerGolemRenderer.cpp create mode 100644 Minecraft.Client/VillagerGolemRenderer.h create mode 100644 Minecraft.Client/VillagerModel.cpp create mode 100644 Minecraft.Client/VillagerModel.h create mode 100644 Minecraft.Client/VillagerRenderer.cpp create mode 100644 Minecraft.Client/VillagerRenderer.h create mode 100644 Minecraft.Client/VillagerZombieModel.cpp create mode 100644 Minecraft.Client/VillagerZombieModel.h create mode 100644 Minecraft.Client/WaterDropParticle.cpp create mode 100644 Minecraft.Client/WaterDropParticle.h create mode 100644 Minecraft.Client/Windows64/GameConfig/Minecraft.spa.h create mode 100644 Minecraft.Client/Windows64/Leaderboards/WindowsLeaderboardManager.cpp create mode 100644 Minecraft.Client/Windows64/Leaderboards/WindowsLeaderboardManager.h create mode 100644 Minecraft.Client/Windows64/Minecraft_Macros.h create mode 100644 Minecraft.Client/Windows64/Network/WinsockNetLayer.cpp create mode 100644 Minecraft.Client/Windows64/Network/WinsockNetLayer.h create mode 100644 Minecraft.Client/Windows64/Resource.h create mode 100644 Minecraft.Client/Windows64/Social/SocialManager.h create mode 100644 Minecraft.Client/Windows64/Windows64_App.cpp create mode 100644 Minecraft.Client/Windows64/Windows64_App.h create mode 100644 Minecraft.Client/Windows64/Windows64_Minecraft.cpp create mode 100644 Minecraft.Client/Windows64/Windows64_UIController.cpp create mode 100644 Minecraft.Client/Windows64/Windows64_UIController.h create mode 100644 Minecraft.Client/Windows64/XML/ATGXmlParser.h create mode 100644 Minecraft.Client/Windows64/Xbox_BuildVer.h create mode 100644 Minecraft.Client/WolfModel.cpp create mode 100644 Minecraft.Client/WolfModel.h create mode 100644 Minecraft.Client/WolfRenderer.cpp create mode 100644 Minecraft.Client/WolfRenderer.h create mode 100644 Minecraft.Client/WstringLookup.cpp create mode 100644 Minecraft.Client/WstringLookup.h create mode 100644 Minecraft.Client/Xbox/GameConfig/ArcadeInfo.xml create mode 100644 Minecraft.Client/Xbox/GameConfig/AvatarPackages/AvatarAwards create mode 100644 Minecraft.Client/Xbox/GameConfig/Minecraft.spa.h create mode 100644 Minecraft.Client/Xbox/Leaderboards/XboxLeaderboardManager.cpp create mode 100644 Minecraft.Client/Xbox/Leaderboards/XboxLeaderboardManager.h create mode 100644 Minecraft.Client/Xbox/Minecraftxex.xml create mode 100644 Minecraft.Client/Xbox/Network/NetworkPlayerXbox.cpp create mode 100644 Minecraft.Client/Xbox/Network/NetworkPlayerXbox.h create mode 100644 Minecraft.Client/Xbox/Network/PlatformNetworkManagerXbox.cpp create mode 100644 Minecraft.Client/Xbox/Network/PlatformNetworkManagerXbox.h create mode 100644 Minecraft.Client/Xbox/Network/extra.h create mode 100644 Minecraft.Client/Xbox/Resource.h create mode 100644 Minecraft.Client/Xbox/Social/SocialManager.cpp create mode 100644 Minecraft.Client/Xbox/Social/SocialManager.h create mode 100644 Minecraft.Client/Xbox/XML/ATGXmlParser.cpp create mode 100644 Minecraft.Client/Xbox/XML/ATGXmlParser.h create mode 100644 Minecraft.Client/Xbox/XML/xmlFilesCallback.h create mode 100644 Minecraft.Client/Xbox/Xbox_App.cpp create mode 100644 Minecraft.Client/Xbox/Xbox_App.h create mode 100644 Minecraft.Client/Xbox/Xbox_BuildVer.h create mode 100644 Minecraft.Client/Xbox/Xbox_Minecraft.cpp create mode 100644 Minecraft.Client/Xbox/Xbox_UIController.cpp create mode 100644 Minecraft.Client/Xbox/Xbox_UIController.h create mode 100644 Minecraft.Client/Xbox/targetver.h create mode 100644 Minecraft.Client/Xbox/xex-dev.xml create mode 100644 Minecraft.Client/Xbox/xex.xml create mode 100644 Minecraft.Client/ZombieModel.cpp create mode 100644 Minecraft.Client/ZombieModel.h create mode 100644 Minecraft.Client/ZombieRenderer.cpp create mode 100644 Minecraft.Client/ZombieRenderer.h create mode 100644 Minecraft.Client/extraX64client.h create mode 100644 Minecraft.Client/glWrapper.cpp create mode 100644 Minecraft.Client/stdafx.cpp create mode 100644 Minecraft.Client/stdafx.h create mode 100644 Minecraft.Client/stubs.cpp create mode 100644 Minecraft.Client/stubs.h create mode 100644 Minecraft.World/AABB.cpp create mode 100644 Minecraft.World/AABB.h create mode 100644 Minecraft.World/Abilities.cpp create mode 100644 Minecraft.World/Abilities.h create mode 100644 Minecraft.World/AbstractContainerMenu.cpp create mode 100644 Minecraft.World/AbstractContainerMenu.h create mode 100644 Minecraft.World/Achievement.cpp create mode 100644 Minecraft.World/Achievement.h create mode 100644 Minecraft.World/Achievements.cpp create mode 100644 Minecraft.World/Achievements.h create mode 100644 Minecraft.World/AddEntityPacket.cpp create mode 100644 Minecraft.World/AddEntityPacket.h create mode 100644 Minecraft.World/AddExperienceOrbPacket.cpp create mode 100644 Minecraft.World/AddExperienceOrbPacket.h create mode 100644 Minecraft.World/AddGlobalEntityPacket.cpp create mode 100644 Minecraft.World/AddGlobalEntityPacket.h create mode 100644 Minecraft.World/AddIslandLayer.cpp create mode 100644 Minecraft.World/AddIslandLayer.h create mode 100644 Minecraft.World/AddMobPacket.cpp create mode 100644 Minecraft.World/AddMobPacket.h create mode 100644 Minecraft.World/AddMushroomIslandLayer.cpp create mode 100644 Minecraft.World/AddMushroomIslandLayer.h create mode 100644 Minecraft.World/AddPaintingPacket.cpp create mode 100644 Minecraft.World/AddPaintingPacket.h create mode 100644 Minecraft.World/AddPlayerPacket.cpp create mode 100644 Minecraft.World/AddPlayerPacket.h create mode 100644 Minecraft.World/AddSnowLayer.cpp create mode 100644 Minecraft.World/AddSnowLayer.h create mode 100644 Minecraft.World/AdminLogCommand.h create mode 100644 Minecraft.World/AgableMob.cpp create mode 100644 Minecraft.World/AgableMob.h create mode 100644 Minecraft.World/AirTile.cpp create mode 100644 Minecraft.World/AirTile.h create mode 100644 Minecraft.World/Animal.cpp create mode 100644 Minecraft.World/Animal.h create mode 100644 Minecraft.World/AnimatePacket.cpp create mode 100644 Minecraft.World/AnimatePacket.h create mode 100644 Minecraft.World/AnvilTile.cpp create mode 100644 Minecraft.World/AnvilTile.h create mode 100644 Minecraft.World/AnvilTileItem.cpp create mode 100644 Minecraft.World/AnvilTileItem.h create mode 100644 Minecraft.World/ArmorDyeRecipe.cpp create mode 100644 Minecraft.World/ArmorDyeRecipe.h create mode 100644 Minecraft.World/ArmorItem.cpp create mode 100644 Minecraft.World/ArmorItem.h create mode 100644 Minecraft.World/ArmorRecipes.cpp create mode 100644 Minecraft.World/ArmorRecipes.h create mode 100644 Minecraft.World/ArmorSlot.cpp create mode 100644 Minecraft.World/ArmorSlot.h create mode 100644 Minecraft.World/ArrayWithLength.h create mode 100644 Minecraft.World/Arrays.h create mode 100644 Minecraft.World/Arrow.cpp create mode 100644 Minecraft.World/Arrow.h create mode 100644 Minecraft.World/ArrowAttackGoal.cpp create mode 100644 Minecraft.World/ArrowAttackGoal.h create mode 100644 Minecraft.World/ArrowDamageEnchantment.cpp create mode 100644 Minecraft.World/ArrowDamageEnchantment.h create mode 100644 Minecraft.World/ArrowFireEnchantment.cpp create mode 100644 Minecraft.World/ArrowFireEnchantment.h create mode 100644 Minecraft.World/ArrowInfiniteEnchantment.cpp create mode 100644 Minecraft.World/ArrowInfiniteEnchantment.h create mode 100644 Minecraft.World/ArrowKnockbackEnchantment.cpp create mode 100644 Minecraft.World/ArrowKnockbackEnchantment.h create mode 100644 Minecraft.World/AuxDataTileItem.cpp create mode 100644 Minecraft.World/AuxDataTileItem.h create mode 100644 Minecraft.World/AvoidPlayerGoal.cpp create mode 100644 Minecraft.World/AvoidPlayerGoal.h create mode 100644 Minecraft.World/AwardStatPacket.cpp create mode 100644 Minecraft.World/AwardStatPacket.h create mode 100644 Minecraft.World/BasicTree.cpp create mode 100644 Minecraft.World/BasicTree.h create mode 100644 Minecraft.World/BasicTypeContainers.cpp create mode 100644 Minecraft.World/BasicTypeContainers.h create mode 100644 Minecraft.World/BeachBiome.cpp create mode 100644 Minecraft.World/BeachBiome.h create mode 100644 Minecraft.World/BedItem.cpp create mode 100644 Minecraft.World/BedItem.h create mode 100644 Minecraft.World/BedTile.cpp create mode 100644 Minecraft.World/BedTile.h create mode 100644 Minecraft.World/BegGoal.cpp create mode 100644 Minecraft.World/BegGoal.h create mode 100644 Minecraft.World/BinaryHeap.cpp create mode 100644 Minecraft.World/BinaryHeap.h create mode 100644 Minecraft.World/Biome.cpp create mode 100644 Minecraft.World/Biome.h create mode 100644 Minecraft.World/BiomeCache.cpp create mode 100644 Minecraft.World/BiomeCache.h create mode 100644 Minecraft.World/BiomeDecorator.cpp create mode 100644 Minecraft.World/BiomeDecorator.h create mode 100644 Minecraft.World/BiomeInitLayer.cpp create mode 100644 Minecraft.World/BiomeInitLayer.h create mode 100644 Minecraft.World/BiomeOverrideLayer.cpp create mode 100644 Minecraft.World/BiomeOverrideLayer.h create mode 100644 Minecraft.World/BiomeSource.cpp create mode 100644 Minecraft.World/BiomeSource.h create mode 100644 Minecraft.World/BirchFeature.cpp create mode 100644 Minecraft.World/BirchFeature.h create mode 100644 Minecraft.World/Blaze.cpp create mode 100644 Minecraft.World/Blaze.h create mode 100644 Minecraft.World/BlockDestructionProgress.cpp create mode 100644 Minecraft.World/BlockDestructionProgress.h create mode 100644 Minecraft.World/BlockGenMethods.cpp create mode 100644 Minecraft.World/BlockGenMethods.h create mode 100644 Minecraft.World/BlockRegionUpdatePacket.cpp create mode 100644 Minecraft.World/BlockRegionUpdatePacket.h create mode 100644 Minecraft.World/BlockReplacements.cpp create mode 100644 Minecraft.World/BlockReplacements.h create mode 100644 Minecraft.World/Boat.cpp create mode 100644 Minecraft.World/Boat.h create mode 100644 Minecraft.World/BoatItem.cpp create mode 100644 Minecraft.World/BoatItem.h create mode 100644 Minecraft.World/BodyControl.cpp create mode 100644 Minecraft.World/BodyControl.h create mode 100644 Minecraft.World/BonusChestFeature.cpp create mode 100644 Minecraft.World/BonusChestFeature.h create mode 100644 Minecraft.World/BookItem.cpp create mode 100644 Minecraft.World/BookItem.h create mode 100644 Minecraft.World/BookshelfTile.cpp create mode 100644 Minecraft.World/BookshelfTile.h create mode 100644 Minecraft.World/BossMob.cpp create mode 100644 Minecraft.World/BossMob.h create mode 100644 Minecraft.World/BossMobPart.cpp create mode 100644 Minecraft.World/BossMobPart.h create mode 100644 Minecraft.World/BottleItem.cpp create mode 100644 Minecraft.World/BottleItem.h create mode 100644 Minecraft.World/BoundingBox.cpp create mode 100644 Minecraft.World/BoundingBox.h create mode 100644 Minecraft.World/BowItem.cpp create mode 100644 Minecraft.World/BowItem.h create mode 100644 Minecraft.World/BowlFoodItem.cpp create mode 100644 Minecraft.World/BowlFoodItem.h create mode 100644 Minecraft.World/BreakDoorGoal.cpp create mode 100644 Minecraft.World/BreakDoorGoal.h create mode 100644 Minecraft.World/BreedGoal.cpp create mode 100644 Minecraft.World/BreedGoal.h create mode 100644 Minecraft.World/BrewingStandMenu.cpp create mode 100644 Minecraft.World/BrewingStandMenu.h create mode 100644 Minecraft.World/BrewingStandTile.cpp create mode 100644 Minecraft.World/BrewingStandTile.h create mode 100644 Minecraft.World/BrewingStandTileEntity.cpp create mode 100644 Minecraft.World/BrewingStandTileEntity.h create mode 100644 Minecraft.World/BucketItem.cpp create mode 100644 Minecraft.World/BucketItem.h create mode 100644 Minecraft.World/Buffer.cpp create mode 100644 Minecraft.World/Buffer.h create mode 100644 Minecraft.World/BufferedOutputStream.cpp create mode 100644 Minecraft.World/BufferedOutputStream.h create mode 100644 Minecraft.World/BufferedReader.cpp create mode 100644 Minecraft.World/BufferedReader.h create mode 100644 Minecraft.World/Bush.cpp create mode 100644 Minecraft.World/Bush.h create mode 100644 Minecraft.World/ButtonTile.cpp create mode 100644 Minecraft.World/ButtonTile.h create mode 100644 Minecraft.World/ByteArrayInputStream.cpp create mode 100644 Minecraft.World/ByteArrayInputStream.h create mode 100644 Minecraft.World/ByteArrayOutputStream.cpp create mode 100644 Minecraft.World/ByteArrayOutputStream.h create mode 100644 Minecraft.World/ByteArrayTag.h create mode 100644 Minecraft.World/ByteBuffer.cpp create mode 100644 Minecraft.World/ByteBuffer.h create mode 100644 Minecraft.World/ByteTag.h create mode 100644 Minecraft.World/C4JThread.cpp create mode 100644 Minecraft.World/C4JThread.h create mode 100644 Minecraft.World/CactusFeature.cpp create mode 100644 Minecraft.World/CactusFeature.h create mode 100644 Minecraft.World/CactusTile.cpp create mode 100644 Minecraft.World/CactusTile.h create mode 100644 Minecraft.World/CakeTile.cpp create mode 100644 Minecraft.World/CakeTile.h create mode 100644 Minecraft.World/CanyonFeature.cpp create mode 100644 Minecraft.World/CanyonFeature.h create mode 100644 Minecraft.World/CarrotOnAStickItem.cpp create mode 100644 Minecraft.World/CarrotOnAStickItem.h create mode 100644 Minecraft.World/CarrotTile.cpp create mode 100644 Minecraft.World/CarrotTile.h create mode 100644 Minecraft.World/CauldronTile.cpp create mode 100644 Minecraft.World/CauldronTile.h create mode 100644 Minecraft.World/CaveFeature.cpp create mode 100644 Minecraft.World/CaveFeature.h create mode 100644 Minecraft.World/CaveSpider.cpp create mode 100644 Minecraft.World/CaveSpider.h create mode 100644 Minecraft.World/ChatAutoCompletePacket.h create mode 100644 Minecraft.World/ChatPacket.cpp create mode 100644 Minecraft.World/ChatPacket.h create mode 100644 Minecraft.World/ChestTile.cpp create mode 100644 Minecraft.World/ChestTile.h create mode 100644 Minecraft.World/ChestTileEntity.cpp create mode 100644 Minecraft.World/ChestTileEntity.h create mode 100644 Minecraft.World/Chicken.cpp create mode 100644 Minecraft.World/Chicken.h create mode 100644 Minecraft.World/ChunkPos.cpp create mode 100644 Minecraft.World/ChunkPos.h create mode 100644 Minecraft.World/ChunkSource.h create mode 100644 Minecraft.World/ChunkStorage.h create mode 100644 Minecraft.World/ChunkStorageProfileDecorator.cpp create mode 100644 Minecraft.World/ChunkStorageProfileDecorator.h create mode 100644 Minecraft.World/ChunkTilesUpdatePacket.cpp create mode 100644 Minecraft.World/ChunkTilesUpdatePacket.h create mode 100644 Minecraft.World/ChunkVisibilityAreaPacket.cpp create mode 100644 Minecraft.World/ChunkVisibilityAreaPacket.h create mode 100644 Minecraft.World/ChunkVisibilityPacket.cpp create mode 100644 Minecraft.World/ChunkVisibilityPacket.h create mode 100644 Minecraft.World/Class.cpp create mode 100644 Minecraft.World/Class.h create mode 100644 Minecraft.World/ClayFeature.cpp create mode 100644 Minecraft.World/ClayFeature.h create mode 100644 Minecraft.World/ClayTile.cpp create mode 100644 Minecraft.World/ClayTile.h create mode 100644 Minecraft.World/ClientCommandPacket.cpp create mode 100644 Minecraft.World/ClientCommandPacket.h create mode 100644 Minecraft.World/ClientInformationPacket.h create mode 100644 Minecraft.World/ClientProtocolPacket.h create mode 100644 Minecraft.World/ClientSideMerchant.cpp create mode 100644 Minecraft.World/ClientSideMerchant.h create mode 100644 Minecraft.World/ClockItem.cpp create mode 100644 Minecraft.World/ClockItem.h create mode 100644 Minecraft.World/ClothDyeRecipes.cpp create mode 100644 Minecraft.World/ClothDyeRecipes.h create mode 100644 Minecraft.World/ClothTile.cpp create mode 100644 Minecraft.World/ClothTile.h create mode 100644 Minecraft.World/ClothTileItem.cpp create mode 100644 Minecraft.World/ClothTileItem.h create mode 100644 Minecraft.World/CoalItem.cpp create mode 100644 Minecraft.World/CoalItem.h create mode 100644 Minecraft.World/CocoaTile.cpp create mode 100644 Minecraft.World/CocoaTile.h create mode 100644 Minecraft.World/Color.cpp create mode 100644 Minecraft.World/Color.h create mode 100644 Minecraft.World/ColoredTileItem.cpp create mode 100644 Minecraft.World/ColoredTileItem.h create mode 100644 Minecraft.World/Command.cpp create mode 100644 Minecraft.World/Command.h create mode 100644 Minecraft.World/CommandDispatcher.cpp create mode 100644 Minecraft.World/CommandDispatcher.h create mode 100644 Minecraft.World/CommandSender.h create mode 100644 Minecraft.World/CommandsEnum.h create mode 100644 Minecraft.World/CommonStats.cpp create mode 100644 Minecraft.World/CommonStats.h create mode 100644 Minecraft.World/CompassItem.cpp create mode 100644 Minecraft.World/CompassItem.h create mode 100644 Minecraft.World/ComplexItem.cpp create mode 100644 Minecraft.World/ComplexItem.h create mode 100644 Minecraft.World/ComplexItemDataPacket.cpp create mode 100644 Minecraft.World/ComplexItemDataPacket.h create mode 100644 Minecraft.World/CompoundContainer.cpp create mode 100644 Minecraft.World/CompoundContainer.h create mode 100644 Minecraft.World/CompoundTag.h create mode 100644 Minecraft.World/CompressedTileStorage.cpp create mode 100644 Minecraft.World/CompressedTileStorage.h create mode 100644 Minecraft.World/Connection.cpp create mode 100644 Minecraft.World/Connection.h create mode 100644 Minecraft.World/ConsoleSaveFile.h create mode 100644 Minecraft.World/ConsoleSaveFileConverter.cpp create mode 100644 Minecraft.World/ConsoleSaveFileConverter.h create mode 100644 Minecraft.World/ConsoleSaveFileIO.h create mode 100644 Minecraft.World/ConsoleSaveFileInputStream.cpp create mode 100644 Minecraft.World/ConsoleSaveFileInputStream.h create mode 100644 Minecraft.World/ConsoleSaveFileOriginal.cpp create mode 100644 Minecraft.World/ConsoleSaveFileOriginal.h create mode 100644 Minecraft.World/ConsoleSaveFileOutputStream.cpp create mode 100644 Minecraft.World/ConsoleSaveFileOutputStream.h create mode 100644 Minecraft.World/ConsoleSaveFileSplit.cpp create mode 100644 Minecraft.World/ConsoleSaveFileSplit.h create mode 100644 Minecraft.World/ConsoleSavePath.h create mode 100644 Minecraft.World/Container.cpp create mode 100644 Minecraft.World/Container.h create mode 100644 Minecraft.World/ContainerAckPacket.cpp create mode 100644 Minecraft.World/ContainerAckPacket.h create mode 100644 Minecraft.World/ContainerButtonClickPacket.cpp create mode 100644 Minecraft.World/ContainerButtonClickPacket.h create mode 100644 Minecraft.World/ContainerClickPacket.cpp create mode 100644 Minecraft.World/ContainerClickPacket.h create mode 100644 Minecraft.World/ContainerClosePacket.cpp create mode 100644 Minecraft.World/ContainerClosePacket.h create mode 100644 Minecraft.World/ContainerMenu.cpp create mode 100644 Minecraft.World/ContainerMenu.h create mode 100644 Minecraft.World/ContainerOpenPacket.cpp create mode 100644 Minecraft.World/ContainerOpenPacket.h create mode 100644 Minecraft.World/ContainerSetContentPacket.cpp create mode 100644 Minecraft.World/ContainerSetContentPacket.h create mode 100644 Minecraft.World/ContainerSetDataPacket.cpp create mode 100644 Minecraft.World/ContainerSetDataPacket.h create mode 100644 Minecraft.World/ContainerSetSlotPacket.cpp create mode 100644 Minecraft.World/ContainerSetSlotPacket.h create mode 100644 Minecraft.World/Control.h create mode 100644 Minecraft.World/ControlledByPlayerGoal.cpp create mode 100644 Minecraft.World/ControlledByPlayerGoal.h create mode 100644 Minecraft.World/Coord.h create mode 100644 Minecraft.World/CoralTile.cpp create mode 100644 Minecraft.World/CoralTile.h create mode 100644 Minecraft.World/Cow.cpp create mode 100644 Minecraft.World/Cow.h create mode 100644 Minecraft.World/CraftItemPacket.cpp create mode 100644 Minecraft.World/CraftItemPacket.h create mode 100644 Minecraft.World/CraftingContainer.cpp create mode 100644 Minecraft.World/CraftingContainer.h create mode 100644 Minecraft.World/CraftingMenu.cpp create mode 100644 Minecraft.World/CraftingMenu.h create mode 100644 Minecraft.World/Creature.cpp create mode 100644 Minecraft.World/Creature.h create mode 100644 Minecraft.World/Creeper.cpp create mode 100644 Minecraft.World/Creeper.h create mode 100644 Minecraft.World/CropTile.cpp create mode 100644 Minecraft.World/CropTile.h create mode 100644 Minecraft.World/CustomLevelSource.cpp create mode 100644 Minecraft.World/CustomLevelSource.h create mode 100644 Minecraft.World/CustomPayloadPacket.cpp create mode 100644 Minecraft.World/CustomPayloadPacket.h create mode 100644 Minecraft.World/DamageEnchantment.cpp create mode 100644 Minecraft.World/DamageEnchantment.h create mode 100644 Minecraft.World/DamageSource.cpp create mode 100644 Minecraft.World/DamageSource.h create mode 100644 Minecraft.World/DataInput.h create mode 100644 Minecraft.World/DataInputStream.cpp create mode 100644 Minecraft.World/DataInputStream.h create mode 100644 Minecraft.World/DataLayer.cpp create mode 100644 Minecraft.World/DataLayer.h create mode 100644 Minecraft.World/DataOutput.h create mode 100644 Minecraft.World/DataOutputStream.cpp create mode 100644 Minecraft.World/DataOutputStream.h create mode 100644 Minecraft.World/DeadBushFeature.cpp create mode 100644 Minecraft.World/DeadBushFeature.h create mode 100644 Minecraft.World/DeadBushTile.cpp create mode 100644 Minecraft.World/DeadBushTile.h create mode 100644 Minecraft.World/DebugOptionsPacket.cpp create mode 100644 Minecraft.World/DebugOptionsPacket.h create mode 100644 Minecraft.World/DecorationMaterial.h create mode 100644 Minecraft.World/DefaultGameModeCommand.cpp create mode 100644 Minecraft.World/DefaultGameModeCommand.h create mode 100644 Minecraft.World/DefendVillageTargetGoal.cpp create mode 100644 Minecraft.World/DefendVillageTargetGoal.h create mode 100644 Minecraft.World/Definitions.h create mode 100644 Minecraft.World/DelayedRelease.cpp create mode 100644 Minecraft.World/DelayedRelease.h create mode 100644 Minecraft.World/DerivedLevelData.cpp create mode 100644 Minecraft.World/DerivedLevelData.h create mode 100644 Minecraft.World/DescFormatter.h create mode 100644 Minecraft.World/DesertBiome.cpp create mode 100644 Minecraft.World/DesertBiome.h create mode 100644 Minecraft.World/DesertWellFeature.cpp create mode 100644 Minecraft.World/DesertWellFeature.h create mode 100644 Minecraft.World/DetectorRailTile.cpp create mode 100644 Minecraft.World/DetectorRailTile.h create mode 100644 Minecraft.World/Difficulty.h create mode 100644 Minecraft.World/DigDurabilityEnchantment.cpp create mode 100644 Minecraft.World/DigDurabilityEnchantment.h create mode 100644 Minecraft.World/DiggerItem.cpp create mode 100644 Minecraft.World/DiggerItem.h create mode 100644 Minecraft.World/DiggingEnchantment.cpp create mode 100644 Minecraft.World/DiggingEnchantment.h create mode 100644 Minecraft.World/Dimension.cpp create mode 100644 Minecraft.World/Dimension.h create mode 100644 Minecraft.World/DiodeTile.cpp create mode 100644 Minecraft.World/DiodeTile.h create mode 100644 Minecraft.World/Direction.cpp create mode 100644 Minecraft.World/Direction.h create mode 100644 Minecraft.World/DirectionalTile.cpp create mode 100644 Minecraft.World/DirectionalTile.h create mode 100644 Minecraft.World/DirectoryLevelStorage.cpp create mode 100644 Minecraft.World/DirectoryLevelStorage.h create mode 100644 Minecraft.World/DirectoryLevelStorageSource.cpp create mode 100644 Minecraft.World/DirectoryLevelStorageSource.h create mode 100644 Minecraft.World/DirtTile.cpp create mode 100644 Minecraft.World/DirtTile.h create mode 100644 Minecraft.World/DisconnectPacket.cpp create mode 100644 Minecraft.World/DisconnectPacket.h create mode 100644 Minecraft.World/DispenserTile.cpp create mode 100644 Minecraft.World/DispenserTile.h create mode 100644 Minecraft.World/DispenserTileEntity.cpp create mode 100644 Minecraft.World/DispenserTileEntity.h create mode 100644 Minecraft.World/Distort.cpp create mode 100644 Minecraft.World/Distort.h create mode 100644 Minecraft.World/DoorInfo.cpp create mode 100644 Minecraft.World/DoorInfo.h create mode 100644 Minecraft.World/DoorInteractGoal.cpp create mode 100644 Minecraft.World/DoorInteractGoal.h create mode 100644 Minecraft.World/DoorItem.cpp create mode 100644 Minecraft.World/DoorItem.h create mode 100644 Minecraft.World/DoorTile.cpp create mode 100644 Minecraft.World/DoorTile.h create mode 100644 Minecraft.World/DoubleTag.h create mode 100644 Minecraft.World/DownfallLayer.cpp create mode 100644 Minecraft.World/DownfallLayer.h create mode 100644 Minecraft.World/DownfallMixerLayer.cpp create mode 100644 Minecraft.World/DownfallMixerLayer.h create mode 100644 Minecraft.World/DragonFireball.cpp create mode 100644 Minecraft.World/DragonFireball.h create mode 100644 Minecraft.World/DungeonFeature.cpp create mode 100644 Minecraft.World/DungeonFeature.h create mode 100644 Minecraft.World/DurangoStats.cpp create mode 100644 Minecraft.World/DurangoStats.h create mode 100644 Minecraft.World/DyePowderItem.cpp create mode 100644 Minecraft.World/DyePowderItem.h create mode 100644 Minecraft.World/EatTileGoal.cpp create mode 100644 Minecraft.World/EatTileGoal.h create mode 100644 Minecraft.World/EggItem.cpp create mode 100644 Minecraft.World/EggItem.h create mode 100644 Minecraft.World/EggTile.cpp create mode 100644 Minecraft.World/EggTile.h create mode 100644 Minecraft.World/Emboss.cpp create mode 100644 Minecraft.World/Emboss.h create mode 100644 Minecraft.World/EmptyLevelChunk.cpp create mode 100644 Minecraft.World/EmptyLevelChunk.h create mode 100644 Minecraft.World/EnchantItemCommand.cpp create mode 100644 Minecraft.World/EnchantItemCommand.h create mode 100644 Minecraft.World/EnchantedBookItem.cpp create mode 100644 Minecraft.World/EnchantedBookItem.h create mode 100644 Minecraft.World/Enchantment.cpp create mode 100644 Minecraft.World/Enchantment.h create mode 100644 Minecraft.World/EnchantmentCategory.cpp create mode 100644 Minecraft.World/EnchantmentCategory.h create mode 100644 Minecraft.World/EnchantmentContainer.cpp create mode 100644 Minecraft.World/EnchantmentContainer.h create mode 100644 Minecraft.World/EnchantmentHelper.cpp create mode 100644 Minecraft.World/EnchantmentHelper.h create mode 100644 Minecraft.World/EnchantmentInstance.cpp create mode 100644 Minecraft.World/EnchantmentInstance.h create mode 100644 Minecraft.World/EnchantmentMenu.cpp create mode 100644 Minecraft.World/EnchantmentMenu.h create mode 100644 Minecraft.World/EnchantmentSlot.h create mode 100644 Minecraft.World/EnchantmentTableEntity.cpp create mode 100644 Minecraft.World/EnchantmentTableEntity.h create mode 100644 Minecraft.World/EnchantmentTableTile.cpp create mode 100644 Minecraft.World/EnchantmentTableTile.h create mode 100644 Minecraft.World/EndPodiumFeature.cpp create mode 100644 Minecraft.World/EndPodiumFeature.h create mode 100644 Minecraft.World/EndTag.h create mode 100644 Minecraft.World/EnderChestTile.cpp create mode 100644 Minecraft.World/EnderChestTile.h create mode 100644 Minecraft.World/EnderChestTileEntity.cpp create mode 100644 Minecraft.World/EnderChestTileEntity.h create mode 100644 Minecraft.World/EnderCrystal.cpp create mode 100644 Minecraft.World/EnderCrystal.h create mode 100644 Minecraft.World/EnderDragon.cpp create mode 100644 Minecraft.World/EnderDragon.h create mode 100644 Minecraft.World/EnderEyeItem.cpp create mode 100644 Minecraft.World/EnderEyeItem.h create mode 100644 Minecraft.World/EnderMan.cpp create mode 100644 Minecraft.World/EnderMan.h create mode 100644 Minecraft.World/EnderpearlItem.cpp create mode 100644 Minecraft.World/EnderpearlItem.h create mode 100644 Minecraft.World/Enemy.cpp create mode 100644 Minecraft.World/Enemy.h create mode 100644 Minecraft.World/Entity.cpp create mode 100644 Minecraft.World/Entity.h create mode 100644 Minecraft.World/EntityActionAtPositionPacket.cpp create mode 100644 Minecraft.World/EntityActionAtPositionPacket.h create mode 100644 Minecraft.World/EntityDamageSource.cpp create mode 100644 Minecraft.World/EntityDamageSource.h create mode 100644 Minecraft.World/EntityEvent.h create mode 100644 Minecraft.World/EntityEventPacket.cpp create mode 100644 Minecraft.World/EntityEventPacket.h create mode 100644 Minecraft.World/EntityIO.cpp create mode 100644 Minecraft.World/EntityIO.h create mode 100644 Minecraft.World/EntityPos.cpp create mode 100644 Minecraft.World/EntityPos.h create mode 100644 Minecraft.World/EntityTile.cpp create mode 100644 Minecraft.World/EntityTile.h create mode 100644 Minecraft.World/Exceptions.h create mode 100644 Minecraft.World/ExperienceCommand.cpp create mode 100644 Minecraft.World/ExperienceCommand.h create mode 100644 Minecraft.World/ExperienceItem.cpp create mode 100644 Minecraft.World/ExperienceItem.h create mode 100644 Minecraft.World/ExperienceOrb.cpp create mode 100644 Minecraft.World/ExperienceOrb.h create mode 100644 Minecraft.World/ExplodePacket.cpp create mode 100644 Minecraft.World/ExplodePacket.h create mode 100644 Minecraft.World/Explosion.cpp create mode 100644 Minecraft.World/Explosion.h create mode 100644 Minecraft.World/ExtremeHillsBiome.cpp create mode 100644 Minecraft.World/ExtremeHillsBiome.h create mode 100644 Minecraft.World/EyeOfEnderSignal.cpp create mode 100644 Minecraft.World/EyeOfEnderSignal.h create mode 100644 Minecraft.World/Facing.cpp create mode 100644 Minecraft.World/Facing.h create mode 100644 Minecraft.World/FallingTile.cpp create mode 100644 Minecraft.World/FallingTile.h create mode 100644 Minecraft.World/FarmTile.cpp create mode 100644 Minecraft.World/FarmTile.h create mode 100644 Minecraft.World/FastNoise.cpp create mode 100644 Minecraft.World/FastNoise.h create mode 100644 Minecraft.World/Feature.cpp create mode 100644 Minecraft.World/Feature.h create mode 100644 Minecraft.World/FenceGateTile.cpp create mode 100644 Minecraft.World/FenceGateTile.h create mode 100644 Minecraft.World/FenceTile.cpp create mode 100644 Minecraft.World/FenceTile.h create mode 100644 Minecraft.World/File.cpp create mode 100644 Minecraft.World/File.h create mode 100644 Minecraft.World/FileFilter.h create mode 100644 Minecraft.World/FileHeader.cpp create mode 100644 Minecraft.World/FileHeader.h create mode 100644 Minecraft.World/FileInputStream.cpp create mode 100644 Minecraft.World/FileInputStream.h create mode 100644 Minecraft.World/FileOutputStream.cpp create mode 100644 Minecraft.World/FileOutputStream.h create mode 100644 Minecraft.World/FilenameFilter.h create mode 100644 Minecraft.World/FireAspectEnchantment.cpp create mode 100644 Minecraft.World/FireAspectEnchantment.h create mode 100644 Minecraft.World/FireChargeItem.cpp create mode 100644 Minecraft.World/FireChargeItem.h create mode 100644 Minecraft.World/FireTile.cpp create mode 100644 Minecraft.World/FireTile.h create mode 100644 Minecraft.World/Fireball.cpp create mode 100644 Minecraft.World/Fireball.h create mode 100644 Minecraft.World/FishingHook.cpp create mode 100644 Minecraft.World/FishingHook.h create mode 100644 Minecraft.World/FishingRodItem.cpp create mode 100644 Minecraft.World/FishingRodItem.h create mode 100644 Minecraft.World/FixedBiomeSource.cpp create mode 100644 Minecraft.World/FixedBiomeSource.h create mode 100644 Minecraft.World/FlatLayer.cpp create mode 100644 Minecraft.World/FlatLayer.h create mode 100644 Minecraft.World/FlatLevelSource.cpp create mode 100644 Minecraft.World/FlatLevelSource.h create mode 100644 Minecraft.World/FleeSunGoal.cpp create mode 100644 Minecraft.World/FleeSunGoal.h create mode 100644 Minecraft.World/FlintAndSteelItem.cpp create mode 100644 Minecraft.World/FlintAndSteelItem.h create mode 100644 Minecraft.World/FlippedIcon.cpp create mode 100644 Minecraft.World/FlippedIcon.h create mode 100644 Minecraft.World/FloatBuffer.cpp create mode 100644 Minecraft.World/FloatBuffer.h create mode 100644 Minecraft.World/FloatGoal.cpp create mode 100644 Minecraft.World/FloatGoal.h create mode 100644 Minecraft.World/FloatTag.h create mode 100644 Minecraft.World/FlowerFeature.cpp create mode 100644 Minecraft.World/FlowerFeature.h create mode 100644 Minecraft.World/FlowerPotTile.cpp create mode 100644 Minecraft.World/FlowerPotTile.h create mode 100644 Minecraft.World/FlyingMob.cpp create mode 100644 Minecraft.World/FlyingMob.h create mode 100644 Minecraft.World/FoliageColor.cpp create mode 100644 Minecraft.World/FoliageColor.h create mode 100644 Minecraft.World/FollowOwnerGoal.cpp create mode 100644 Minecraft.World/FollowOwnerGoal.h create mode 100644 Minecraft.World/FollowParentGoal.cpp create mode 100644 Minecraft.World/FollowParentGoal.h create mode 100644 Minecraft.World/FoodConstants.cpp create mode 100644 Minecraft.World/FoodConstants.h create mode 100644 Minecraft.World/FoodData.cpp create mode 100644 Minecraft.World/FoodData.h create mode 100644 Minecraft.World/FoodItem.cpp create mode 100644 Minecraft.World/FoodItem.h create mode 100644 Minecraft.World/FoodRecipies.cpp create mode 100644 Minecraft.World/FoodRecipies.h create mode 100644 Minecraft.World/ForestBiome.cpp create mode 100644 Minecraft.World/ForestBiome.h create mode 100644 Minecraft.World/FurnaceMenu.cpp create mode 100644 Minecraft.World/FurnaceMenu.h create mode 100644 Minecraft.World/FurnaceRecipes.cpp create mode 100644 Minecraft.World/FurnaceRecipes.h create mode 100644 Minecraft.World/FurnaceResultSlot.cpp create mode 100644 Minecraft.World/FurnaceResultSlot.h create mode 100644 Minecraft.World/FurnaceTile.cpp create mode 100644 Minecraft.World/FurnaceTile.h create mode 100644 Minecraft.World/FurnaceTileEntity.cpp create mode 100644 Minecraft.World/FurnaceTileEntity.h create mode 100644 Minecraft.World/FuzzyZoomLayer.cpp create mode 100644 Minecraft.World/FuzzyZoomLayer.h create mode 100644 Minecraft.World/GZIPInputStream.h create mode 100644 Minecraft.World/GZIPOutputStream.h create mode 100644 Minecraft.World/GameCommandPacket.cpp create mode 100644 Minecraft.World/GameCommandPacket.h create mode 100644 Minecraft.World/GameEventPacket.cpp create mode 100644 Minecraft.World/GameEventPacket.h create mode 100644 Minecraft.World/GameModeCommand.cpp create mode 100644 Minecraft.World/GameModeCommand.h create mode 100644 Minecraft.World/GasMaterial.h create mode 100644 Minecraft.World/GeneralStat.cpp create mode 100644 Minecraft.World/GeneralStat.h create mode 100644 Minecraft.World/GenericStats.cpp create mode 100644 Minecraft.World/GenericStats.h create mode 100644 Minecraft.World/GetInfoPacket.cpp create mode 100644 Minecraft.World/GetInfoPacket.h create mode 100644 Minecraft.World/Ghast.cpp create mode 100644 Minecraft.World/Ghast.h create mode 100644 Minecraft.World/Giant.cpp create mode 100644 Minecraft.World/Giant.h create mode 100644 Minecraft.World/GiveItemCommand.cpp create mode 100644 Minecraft.World/GiveItemCommand.h create mode 100644 Minecraft.World/GlassTile.cpp create mode 100644 Minecraft.World/GlassTile.h create mode 100644 Minecraft.World/GlobalEntity.cpp create mode 100644 Minecraft.World/GlobalEntity.h create mode 100644 Minecraft.World/Goal.cpp create mode 100644 Minecraft.World/Goal.h create mode 100644 Minecraft.World/GoalSelector.cpp create mode 100644 Minecraft.World/GoalSelector.h create mode 100644 Minecraft.World/GoldenAppleItem.cpp create mode 100644 Minecraft.World/GoldenAppleItem.h create mode 100644 Minecraft.World/Golem.cpp create mode 100644 Minecraft.World/Golem.h create mode 100644 Minecraft.World/GrassColor.cpp create mode 100644 Minecraft.World/GrassColor.h create mode 100644 Minecraft.World/GrassTile.cpp create mode 100644 Minecraft.World/GrassTile.h create mode 100644 Minecraft.World/GravelTile.cpp create mode 100644 Minecraft.World/GravelTile.h create mode 100644 Minecraft.World/GroundBushFeature.cpp create mode 100644 Minecraft.World/GroundBushFeature.h create mode 100644 Minecraft.World/GrowMushroomIslandLayer.cpp create mode 100644 Minecraft.World/GrowMushroomIslandLayer.h create mode 100644 Minecraft.World/HalfSlabTile.cpp create mode 100644 Minecraft.World/HalfSlabTile.h create mode 100644 Minecraft.World/HalfTransparentTile.cpp create mode 100644 Minecraft.World/HalfTransparentTile.h create mode 100644 Minecraft.World/HangingEntity.cpp create mode 100644 Minecraft.World/HangingEntity.h create mode 100644 Minecraft.World/HangingEntityItem.cpp create mode 100644 Minecraft.World/HangingEntityItem.h create mode 100644 Minecraft.World/HashExtension.h create mode 100644 Minecraft.World/Hasher.cpp create mode 100644 Minecraft.World/Hasher.h create mode 100644 Minecraft.World/HatchetItem.cpp create mode 100644 Minecraft.World/HatchetItem.h create mode 100644 Minecraft.World/HeavyTile.cpp create mode 100644 Minecraft.World/HeavyTile.h create mode 100644 Minecraft.World/HellBiome.cpp create mode 100644 Minecraft.World/HellBiome.h create mode 100644 Minecraft.World/HellDimension.cpp create mode 100644 Minecraft.World/HellDimension.h create mode 100644 Minecraft.World/HellFireFeature.cpp create mode 100644 Minecraft.World/HellFireFeature.h create mode 100644 Minecraft.World/HellFlatLevelSource.cpp create mode 100644 Minecraft.World/HellFlatLevelSource.h create mode 100644 Minecraft.World/HellPortalFeature.cpp create mode 100644 Minecraft.World/HellPortalFeature.h create mode 100644 Minecraft.World/HellRandomLevelSource.cpp create mode 100644 Minecraft.World/HellRandomLevelSource.h create mode 100644 Minecraft.World/HellSandTile.cpp create mode 100644 Minecraft.World/HellSandTile.h create mode 100644 Minecraft.World/HellSpringFeature.cpp create mode 100644 Minecraft.World/HellSpringFeature.h create mode 100644 Minecraft.World/HellStoneTile.cpp create mode 100644 Minecraft.World/HellStoneTile.h create mode 100644 Minecraft.World/HitResult.cpp create mode 100644 Minecraft.World/HitResult.h create mode 100644 Minecraft.World/HoeItem.cpp create mode 100644 Minecraft.World/HoeItem.h create mode 100644 Minecraft.World/HouseFeature.cpp create mode 100644 Minecraft.World/HouseFeature.h create mode 100644 Minecraft.World/HugeMushroomFeature.cpp create mode 100644 Minecraft.World/HugeMushroomFeature.h create mode 100644 Minecraft.World/HugeMushroomTile.cpp create mode 100644 Minecraft.World/HugeMushroomTile.h create mode 100644 Minecraft.World/HurtByTargetGoal.cpp create mode 100644 Minecraft.World/HurtByTargetGoal.h create mode 100644 Minecraft.World/I18n.cpp create mode 100644 Minecraft.World/I18n.h create mode 100644 Minecraft.World/IceBiome.cpp create mode 100644 Minecraft.World/IceBiome.h create mode 100644 Minecraft.World/IceTile.cpp create mode 100644 Minecraft.World/IceTile.h create mode 100644 Minecraft.World/Icon.h create mode 100644 Minecraft.World/IconRegister.h create mode 100644 Minecraft.World/ImprovedNoise.cpp create mode 100644 Minecraft.World/ImprovedNoise.h create mode 100644 Minecraft.World/IndirectEntityDamageSource.cpp create mode 100644 Minecraft.World/IndirectEntityDamageSource.h create mode 100644 Minecraft.World/InputOutputStream.h create mode 100644 Minecraft.World/InputStream.cpp create mode 100644 Minecraft.World/InputStream.h create mode 100644 Minecraft.World/InputStreamReader.cpp create mode 100644 Minecraft.World/InputStreamReader.h create mode 100644 Minecraft.World/InstantenousMobEffect.cpp create mode 100644 Minecraft.World/InstantenousMobEffect.h create mode 100644 Minecraft.World/IntArrayTag.h create mode 100644 Minecraft.World/IntBuffer.cpp create mode 100644 Minecraft.World/IntBuffer.h create mode 100644 Minecraft.World/IntCache.cpp create mode 100644 Minecraft.World/IntCache.h create mode 100644 Minecraft.World/IntTag.h create mode 100644 Minecraft.World/InteractGoal.cpp create mode 100644 Minecraft.World/InteractGoal.h create mode 100644 Minecraft.World/InteractPacket.cpp create mode 100644 Minecraft.World/InteractPacket.h create mode 100644 Minecraft.World/Inventory.cpp create mode 100644 Minecraft.World/Inventory.h create mode 100644 Minecraft.World/InventoryMenu.cpp create mode 100644 Minecraft.World/InventoryMenu.h create mode 100644 Minecraft.World/IslandLayer.cpp create mode 100644 Minecraft.World/IslandLayer.h create mode 100644 Minecraft.World/Item.cpp create mode 100644 Minecraft.World/Item.h create mode 100644 Minecraft.World/ItemEntity.cpp create mode 100644 Minecraft.World/ItemEntity.h create mode 100644 Minecraft.World/ItemFrame.cpp create mode 100644 Minecraft.World/ItemFrame.h create mode 100644 Minecraft.World/ItemInstance.cpp create mode 100644 Minecraft.World/ItemInstance.h create mode 100644 Minecraft.World/ItemStat.cpp create mode 100644 Minecraft.World/ItemStat.h create mode 100644 Minecraft.World/JavaIntHash.h create mode 100644 Minecraft.World/JavaMath.cpp create mode 100644 Minecraft.World/JavaMath.h create mode 100644 Minecraft.World/JumpControl.cpp create mode 100644 Minecraft.World/JumpControl.h create mode 100644 Minecraft.World/JungleBiome.cpp create mode 100644 Minecraft.World/JungleBiome.h create mode 100644 Minecraft.World/KeepAlivePacket.cpp create mode 100644 Minecraft.World/KeepAlivePacket.h create mode 100644 Minecraft.World/KickPlayerPacket.cpp create mode 100644 Minecraft.World/KickPlayerPacket.h create mode 100644 Minecraft.World/KillCommand.cpp create mode 100644 Minecraft.World/KillCommand.h create mode 100644 Minecraft.World/KnockbackEnchantment.cpp create mode 100644 Minecraft.World/KnockbackEnchantment.h create mode 100644 Minecraft.World/LadderTile.cpp create mode 100644 Minecraft.World/LadderTile.h create mode 100644 Minecraft.World/LakeFeature.cpp create mode 100644 Minecraft.World/LakeFeature.h create mode 100644 Minecraft.World/Language.cpp create mode 100644 Minecraft.World/Language.h create mode 100644 Minecraft.World/LargeCaveFeature.cpp create mode 100644 Minecraft.World/LargeCaveFeature.h create mode 100644 Minecraft.World/LargeFeature.cpp create mode 100644 Minecraft.World/LargeFeature.h create mode 100644 Minecraft.World/LargeHellCaveFeature.cpp create mode 100644 Minecraft.World/LargeHellCaveFeature.h create mode 100644 Minecraft.World/LavaSlime.cpp create mode 100644 Minecraft.World/LavaSlime.h create mode 100644 Minecraft.World/Layer.cpp create mode 100644 Minecraft.World/Layer.h create mode 100644 Minecraft.World/LeafTile.cpp create mode 100644 Minecraft.World/LeafTile.h create mode 100644 Minecraft.World/LeafTileItem.cpp create mode 100644 Minecraft.World/LeafTileItem.h create mode 100644 Minecraft.World/LeapAtTargetGoal.cpp create mode 100644 Minecraft.World/LeapAtTargetGoal.h create mode 100644 Minecraft.World/Level.cpp create mode 100644 Minecraft.World/Level.h create mode 100644 Minecraft.World/LevelChunk.cpp create mode 100644 Minecraft.World/LevelChunk.h create mode 100644 Minecraft.World/LevelConflictException.cpp create mode 100644 Minecraft.World/LevelConflictException.h create mode 100644 Minecraft.World/LevelData.cpp create mode 100644 Minecraft.World/LevelData.h create mode 100644 Minecraft.World/LevelEvent.h create mode 100644 Minecraft.World/LevelEventPacket.cpp create mode 100644 Minecraft.World/LevelEventPacket.h create mode 100644 Minecraft.World/LevelListener.h create mode 100644 Minecraft.World/LevelObjectInputStream.h create mode 100644 Minecraft.World/LevelSettings.cpp create mode 100644 Minecraft.World/LevelSettings.h create mode 100644 Minecraft.World/LevelSoundPacket.cpp create mode 100644 Minecraft.World/LevelSoundPacket.h create mode 100644 Minecraft.World/LevelSource.h create mode 100644 Minecraft.World/LevelStorage.cpp create mode 100644 Minecraft.World/LevelStorage.h create mode 100644 Minecraft.World/LevelStorageProfilerDecorator.cpp create mode 100644 Minecraft.World/LevelStorageProfilerDecorator.h create mode 100644 Minecraft.World/LevelStorageSource.h create mode 100644 Minecraft.World/LevelSummary.cpp create mode 100644 Minecraft.World/LevelSummary.h create mode 100644 Minecraft.World/LevelType.cpp create mode 100644 Minecraft.World/LevelType.h create mode 100644 Minecraft.World/LeverTile.cpp create mode 100644 Minecraft.World/LeverTile.h create mode 100644 Minecraft.World/LightGemFeature.cpp create mode 100644 Minecraft.World/LightGemFeature.h create mode 100644 Minecraft.World/LightGemTile.cpp create mode 100644 Minecraft.World/LightGemTile.h create mode 100644 Minecraft.World/LightLayer.h create mode 100644 Minecraft.World/LightningBolt.cpp create mode 100644 Minecraft.World/LightningBolt.h create mode 100644 Minecraft.World/LiquidMaterial.h create mode 100644 Minecraft.World/LiquidTile.cpp create mode 100644 Minecraft.World/LiquidTile.h create mode 100644 Minecraft.World/LiquidTileDynamic.cpp create mode 100644 Minecraft.World/LiquidTileDynamic.h create mode 100644 Minecraft.World/LiquidTileStatic.cpp create mode 100644 Minecraft.World/LiquidTileStatic.h create mode 100644 Minecraft.World/ListTag.h create mode 100644 Minecraft.World/LockedChestTile.cpp create mode 100644 Minecraft.World/LockedChestTile.h create mode 100644 Minecraft.World/LoginPacket.cpp create mode 100644 Minecraft.World/LoginPacket.h create mode 100644 Minecraft.World/LongTag.h create mode 100644 Minecraft.World/LookAtPlayerGoal.cpp create mode 100644 Minecraft.World/LookAtPlayerGoal.h create mode 100644 Minecraft.World/LookAtTradingPlayerGoal.cpp create mode 100644 Minecraft.World/LookAtTradingPlayerGoal.h create mode 100644 Minecraft.World/LookControl.cpp create mode 100644 Minecraft.World/LookControl.h create mode 100644 Minecraft.World/LootBonusEnchantment.cpp create mode 100644 Minecraft.World/LootBonusEnchantment.h create mode 100644 Minecraft.World/MakeLoveGoal.cpp create mode 100644 Minecraft.World/MakeLoveGoal.h create mode 100644 Minecraft.World/MapItem.cpp create mode 100644 Minecraft.World/MapItem.h create mode 100644 Minecraft.World/MapItemSavedData.cpp create mode 100644 Minecraft.World/MapItemSavedData.h create mode 100644 Minecraft.World/Material.cpp create mode 100644 Minecraft.World/Material.h create mode 100644 Minecraft.World/MaterialColor.cpp create mode 100644 Minecraft.World/MaterialColor.h create mode 100644 Minecraft.World/McRegionChunkStorage.cpp create mode 100644 Minecraft.World/McRegionChunkStorage.h create mode 100644 Minecraft.World/McRegionLevelStorage.cpp create mode 100644 Minecraft.World/McRegionLevelStorage.h create mode 100644 Minecraft.World/McRegionLevelStorageSource.cpp create mode 100644 Minecraft.World/McRegionLevelStorageSource.h create mode 100644 Minecraft.World/MegaTreeFeature.cpp create mode 100644 Minecraft.World/MegaTreeFeature.h create mode 100644 Minecraft.World/MeleeAttackGoal.cpp create mode 100644 Minecraft.World/MeleeAttackGoal.h create mode 100644 Minecraft.World/MelonTile.cpp create mode 100644 Minecraft.World/MelonTile.h create mode 100644 Minecraft.World/MemoryChunkStorage.cpp create mode 100644 Minecraft.World/MemoryChunkStorage.h create mode 100644 Minecraft.World/MemoryLevelStorage.cpp create mode 100644 Minecraft.World/MemoryLevelStorage.h create mode 100644 Minecraft.World/MemoryLevelStorageSource.cpp create mode 100644 Minecraft.World/MemoryLevelStorageSource.h create mode 100644 Minecraft.World/MenuBackup.cpp create mode 100644 Minecraft.World/MenuBackup.h create mode 100644 Minecraft.World/Merchant.h create mode 100644 Minecraft.World/MerchantContainer.cpp create mode 100644 Minecraft.World/MerchantContainer.h create mode 100644 Minecraft.World/MerchantMenu.cpp create mode 100644 Minecraft.World/MerchantMenu.h create mode 100644 Minecraft.World/MerchantRecipe.cpp create mode 100644 Minecraft.World/MerchantRecipe.h create mode 100644 Minecraft.World/MerchantRecipeList.cpp create mode 100644 Minecraft.World/MerchantRecipeList.h create mode 100644 Minecraft.World/MerchantResultSlot.cpp create mode 100644 Minecraft.World/MerchantResultSlot.h create mode 100644 Minecraft.World/MetalTile.cpp create mode 100644 Minecraft.World/MetalTile.h create mode 100644 Minecraft.World/MilkBucketItem.cpp create mode 100644 Minecraft.World/MilkBucketItem.h create mode 100644 Minecraft.World/MineShaftFeature.cpp create mode 100644 Minecraft.World/MineShaftFeature.h create mode 100644 Minecraft.World/MineShaftPieces.cpp create mode 100644 Minecraft.World/MineShaftPieces.h create mode 100644 Minecraft.World/MineShaftStart.cpp create mode 100644 Minecraft.World/MineShaftStart.h create mode 100644 Minecraft.World/Minecart.cpp create mode 100644 Minecraft.World/Minecart.h create mode 100644 Minecraft.World/MinecartItem.cpp create mode 100644 Minecraft.World/MinecartItem.h create mode 100644 Minecraft.World/Minecraft.World.cpp create mode 100644 Minecraft.World/Minecraft.World.h create mode 100644 Minecraft.World/Minecraft.World.vcxproj create mode 100644 Minecraft.World/Minecraft.World.vcxproj.filters create mode 100644 Minecraft.World/Mob.cpp create mode 100644 Minecraft.World/Mob.h create mode 100644 Minecraft.World/MobCategory.cpp create mode 100644 Minecraft.World/MobCategory.h create mode 100644 Minecraft.World/MobEffect.cpp create mode 100644 Minecraft.World/MobEffect.h create mode 100644 Minecraft.World/MobEffectInstance.cpp create mode 100644 Minecraft.World/MobEffectInstance.h create mode 100644 Minecraft.World/MobSpawner.cpp create mode 100644 Minecraft.World/MobSpawner.h create mode 100644 Minecraft.World/MobSpawnerTile.cpp create mode 100644 Minecraft.World/MobSpawnerTile.h create mode 100644 Minecraft.World/MobSpawnerTileEntity.cpp create mode 100644 Minecraft.World/MobSpawnerTileEntity.h create mode 100644 Minecraft.World/MobType.h create mode 100644 Minecraft.World/MockedLevelStorage.cpp create mode 100644 Minecraft.World/MockedLevelStorage.h create mode 100644 Minecraft.World/Monster.cpp create mode 100644 Minecraft.World/Monster.h create mode 100644 Minecraft.World/MonsterPlacerItem.cpp create mode 100644 Minecraft.World/MonsterPlacerItem.h create mode 100644 Minecraft.World/MonsterRoomFeature.cpp create mode 100644 Minecraft.World/MonsterRoomFeature.h create mode 100644 Minecraft.World/MouseInventoryClickHandler.h create mode 100644 Minecraft.World/MoveControl.cpp create mode 100644 Minecraft.World/MoveControl.h create mode 100644 Minecraft.World/MoveEntityPacket.cpp create mode 100644 Minecraft.World/MoveEntityPacket.h create mode 100644 Minecraft.World/MoveEntityPacketSmall.cpp create mode 100644 Minecraft.World/MoveEntityPacketSmall.h create mode 100644 Minecraft.World/MoveIndoorsGoal.cpp create mode 100644 Minecraft.World/MoveIndoorsGoal.h create mode 100644 Minecraft.World/MovePlayerPacket.cpp create mode 100644 Minecraft.World/MovePlayerPacket.h create mode 100644 Minecraft.World/MoveThroughVillageGoal.cpp create mode 100644 Minecraft.World/MoveThroughVillageGoal.h create mode 100644 Minecraft.World/MoveTowardsRestrictionGoal.cpp create mode 100644 Minecraft.World/MoveTowardsRestrictionGoal.h create mode 100644 Minecraft.World/MoveTowardsTargetGoal.cpp create mode 100644 Minecraft.World/MoveTowardsTargetGoal.h create mode 100644 Minecraft.World/Mth.cpp create mode 100644 Minecraft.World/Mth.h create mode 100644 Minecraft.World/MultiTextureTileItem.cpp create mode 100644 Minecraft.World/MultiTextureTileItem.h create mode 100644 Minecraft.World/Mushroom.cpp create mode 100644 Minecraft.World/Mushroom.h create mode 100644 Minecraft.World/MushroomCow.cpp create mode 100644 Minecraft.World/MushroomCow.h create mode 100644 Minecraft.World/MushroomIslandBiome.cpp create mode 100644 Minecraft.World/MushroomIslandBiome.h create mode 100644 Minecraft.World/MusicTile.cpp create mode 100644 Minecraft.World/MusicTile.h create mode 100644 Minecraft.World/MusicTileEntity.cpp create mode 100644 Minecraft.World/MusicTileEntity.h create mode 100644 Minecraft.World/MycelTile.cpp create mode 100644 Minecraft.World/MycelTile.h create mode 100644 Minecraft.World/NbtIo.cpp create mode 100644 Minecraft.World/NbtIo.h create mode 100644 Minecraft.World/NbtSlotFile.cpp create mode 100644 Minecraft.World/NbtSlotFile.h create mode 100644 Minecraft.World/NearestAttackableTargetGoal.cpp create mode 100644 Minecraft.World/NearestAttackableTargetGoal.h create mode 100644 Minecraft.World/NetherBridgeFeature.cpp create mode 100644 Minecraft.World/NetherBridgeFeature.h create mode 100644 Minecraft.World/NetherBridgePieces.cpp create mode 100644 Minecraft.World/NetherBridgePieces.h create mode 100644 Minecraft.World/NetherSphere.cpp create mode 100644 Minecraft.World/NetherSphere.h create mode 100644 Minecraft.World/NetherStalkTile.cpp create mode 100644 Minecraft.World/NetherStalkTile.h create mode 100644 Minecraft.World/Node.cpp create mode 100644 Minecraft.World/Node.h create mode 100644 Minecraft.World/NonTameRandomTargetGoal.cpp create mode 100644 Minecraft.World/NonTameRandomTargetGoal.h create mode 100644 Minecraft.World/NormalDimension.h create mode 100644 Minecraft.World/NotGateTile.cpp create mode 100644 Minecraft.World/NotGateTile.h create mode 100644 Minecraft.World/Npc.cpp create mode 100644 Minecraft.World/Npc.h create mode 100644 Minecraft.World/NumberFormaters.h create mode 100644 Minecraft.World/ObsidianTile.cpp create mode 100644 Minecraft.World/ObsidianTile.h create mode 100644 Minecraft.World/OceanBiome.h create mode 100644 Minecraft.World/OcelotSitOnTileGoal.cpp create mode 100644 Minecraft.World/OcelotSitOnTileGoal.h create mode 100644 Minecraft.World/OfferFlowerGoal.cpp create mode 100644 Minecraft.World/OfferFlowerGoal.h create mode 100644 Minecraft.World/OldChunkStorage.cpp create mode 100644 Minecraft.World/OldChunkStorage.h create mode 100644 Minecraft.World/OpenDoorGoal.cpp create mode 100644 Minecraft.World/OpenDoorGoal.h create mode 100644 Minecraft.World/OreFeature.cpp create mode 100644 Minecraft.World/OreFeature.h create mode 100644 Minecraft.World/OreRecipies.cpp create mode 100644 Minecraft.World/OreRecipies.h create mode 100644 Minecraft.World/OreTile.cpp create mode 100644 Minecraft.World/OreTile.h create mode 100644 Minecraft.World/OutputStream.h create mode 100644 Minecraft.World/OwnerHurtByTargetGoal.cpp create mode 100644 Minecraft.World/OwnerHurtByTargetGoal.h create mode 100644 Minecraft.World/OwnerHurtTargetGoal.cpp create mode 100644 Minecraft.World/OwnerHurtTargetGoal.h create mode 100644 Minecraft.World/OxygenEnchantment.cpp create mode 100644 Minecraft.World/OxygenEnchantment.h create mode 100644 Minecraft.World/Ozelot.cpp create mode 100644 Minecraft.World/Ozelot.h create mode 100644 Minecraft.World/OzelotAttackGoal.cpp create mode 100644 Minecraft.World/OzelotAttackGoal.h create mode 100644 Minecraft.World/Packet.cpp create mode 100644 Minecraft.World/Packet.h create mode 100644 Minecraft.World/PacketListener.cpp create mode 100644 Minecraft.World/PacketListener.h create mode 100644 Minecraft.World/Painting.cpp create mode 100644 Minecraft.World/Painting.h create mode 100644 Minecraft.World/PanicGoal.cpp create mode 100644 Minecraft.World/PanicGoal.h create mode 100644 Minecraft.World/ParticleTypes.h create mode 100644 Minecraft.World/Path.cpp create mode 100644 Minecraft.World/Path.h create mode 100644 Minecraft.World/PathFinder.cpp create mode 100644 Minecraft.World/PathFinder.h create mode 100644 Minecraft.World/PathNavigation.cpp create mode 100644 Minecraft.World/PathNavigation.h create mode 100644 Minecraft.World/PathfinderMob.cpp create mode 100644 Minecraft.World/PathfinderMob.h create mode 100644 Minecraft.World/PerformanceTimer.cpp create mode 100644 Minecraft.World/PerformanceTimer.h create mode 100644 Minecraft.World/PerlinNoise.cpp create mode 100644 Minecraft.World/PerlinNoise.h create mode 100644 Minecraft.World/PerlinSimplexNoise.cpp create mode 100644 Minecraft.World/PerlinSimplexNoise.h create mode 100644 Minecraft.World/PickaxeItem.cpp create mode 100644 Minecraft.World/PickaxeItem.h create mode 100644 Minecraft.World/Pig.cpp create mode 100644 Minecraft.World/Pig.h create mode 100644 Minecraft.World/PigZombie.cpp create mode 100644 Minecraft.World/PigZombie.h create mode 100644 Minecraft.World/PineFeature.cpp create mode 100644 Minecraft.World/PineFeature.h create mode 100644 Minecraft.World/PistonBaseTile.cpp create mode 100644 Minecraft.World/PistonBaseTile.h create mode 100644 Minecraft.World/PistonExtensionTile.cpp create mode 100644 Minecraft.World/PistonExtensionTile.h create mode 100644 Minecraft.World/PistonMovingPiece.cpp create mode 100644 Minecraft.World/PistonMovingPiece.h create mode 100644 Minecraft.World/PistonPieceEntity.cpp create mode 100644 Minecraft.World/PistonPieceEntity.h create mode 100644 Minecraft.World/PistonTileItem.cpp create mode 100644 Minecraft.World/PistonTileItem.h create mode 100644 Minecraft.World/PlainsBiome.cpp create mode 100644 Minecraft.World/PlainsBiome.h create mode 100644 Minecraft.World/PlayGoal.cpp create mode 100644 Minecraft.World/PlayGoal.h create mode 100644 Minecraft.World/Player.cpp create mode 100644 Minecraft.World/Player.h create mode 100644 Minecraft.World/PlayerAbilitiesPacket.cpp create mode 100644 Minecraft.World/PlayerAbilitiesPacket.h create mode 100644 Minecraft.World/PlayerActionPacket.cpp create mode 100644 Minecraft.World/PlayerActionPacket.h create mode 100644 Minecraft.World/PlayerCommandPacket.cpp create mode 100644 Minecraft.World/PlayerCommandPacket.h create mode 100644 Minecraft.World/PlayerEnderChestContainer.cpp create mode 100644 Minecraft.World/PlayerEnderChestContainer.h create mode 100644 Minecraft.World/PlayerIO.h create mode 100644 Minecraft.World/PlayerInfoPacket.cpp create mode 100644 Minecraft.World/PlayerInfoPacket.h create mode 100644 Minecraft.World/PlayerInputPacket.cpp create mode 100644 Minecraft.World/PlayerInputPacket.h create mode 100644 Minecraft.World/PortalForcer.cpp create mode 100644 Minecraft.World/PortalForcer.h create mode 100644 Minecraft.World/PortalMaterial.h create mode 100644 Minecraft.World/PortalTile.cpp create mode 100644 Minecraft.World/PortalTile.h create mode 100644 Minecraft.World/Pos.cpp create mode 100644 Minecraft.World/Pos.h create mode 100644 Minecraft.World/PotatoTile.cpp create mode 100644 Minecraft.World/PotatoTile.h create mode 100644 Minecraft.World/PotionBrewing.cpp create mode 100644 Minecraft.World/PotionBrewing.h create mode 100644 Minecraft.World/PotionItem.cpp create mode 100644 Minecraft.World/PotionItem.h create mode 100644 Minecraft.World/PreLoginPacket.cpp create mode 100644 Minecraft.World/PreLoginPacket.h create mode 100644 Minecraft.World/PressurePlateTile.cpp create mode 100644 Minecraft.World/PressurePlateTile.h create mode 100644 Minecraft.World/PrimedTnt.cpp create mode 100644 Minecraft.World/PrimedTnt.h create mode 100644 Minecraft.World/ProgressListener.h create mode 100644 Minecraft.World/ProtectionEnchantment.cpp create mode 100644 Minecraft.World/ProtectionEnchantment.h create mode 100644 Minecraft.World/PumpkinFeature.cpp create mode 100644 Minecraft.World/PumpkinFeature.h create mode 100644 Minecraft.World/PumpkinTile.cpp create mode 100644 Minecraft.World/PumpkinTile.h create mode 100644 Minecraft.World/QuartzBlockTile.cpp create mode 100644 Minecraft.World/QuartzBlockTile.h create mode 100644 Minecraft.World/RailTile.cpp create mode 100644 Minecraft.World/RailTile.h create mode 100644 Minecraft.World/RainforestBiome.cpp create mode 100644 Minecraft.World/RainforestBiome.h create mode 100644 Minecraft.World/Random.cpp create mode 100644 Minecraft.World/Random.h create mode 100644 Minecraft.World/RandomLevelSource.cpp create mode 100644 Minecraft.World/RandomLevelSource.h create mode 100644 Minecraft.World/RandomLookAroundGoal.cpp create mode 100644 Minecraft.World/RandomLookAroundGoal.h create mode 100644 Minecraft.World/RandomPos.cpp create mode 100644 Minecraft.World/RandomPos.h create mode 100644 Minecraft.World/RandomScatteredLargeFeature.cpp create mode 100644 Minecraft.World/RandomScatteredLargeFeature.h create mode 100644 Minecraft.World/RandomStrollGoal.cpp create mode 100644 Minecraft.World/RandomStrollGoal.h create mode 100644 Minecraft.World/Rarity.cpp create mode 100644 Minecraft.World/Rarity.h create mode 100644 Minecraft.World/ReadMe.txt create mode 100644 Minecraft.World/ReadOnlyChunkCache.cpp create mode 100644 Minecraft.World/ReadOnlyChunkCache.h create mode 100644 Minecraft.World/Reader.h create mode 100644 Minecraft.World/Recipes.cpp create mode 100644 Minecraft.World/Recipes.h create mode 100644 Minecraft.World/Recipy.h create mode 100644 Minecraft.World/RecordPlayerTile.cpp create mode 100644 Minecraft.World/RecordPlayerTile.h create mode 100644 Minecraft.World/RecordingItem.cpp create mode 100644 Minecraft.World/RecordingItem.h create mode 100644 Minecraft.World/RedStoneDustTile.cpp create mode 100644 Minecraft.World/RedStoneDustTile.h create mode 100644 Minecraft.World/RedStoneItem.cpp create mode 100644 Minecraft.World/RedStoneItem.h create mode 100644 Minecraft.World/RedStoneOreTile.cpp create mode 100644 Minecraft.World/RedStoneOreTile.h create mode 100644 Minecraft.World/RedlightTile.cpp create mode 100644 Minecraft.World/RedlightTile.h create mode 100644 Minecraft.World/ReedTile.cpp create mode 100644 Minecraft.World/ReedTile.h create mode 100644 Minecraft.World/ReedsFeature.cpp create mode 100644 Minecraft.World/ReedsFeature.h create mode 100644 Minecraft.World/Reference.h create mode 100644 Minecraft.World/Region.cpp create mode 100644 Minecraft.World/Region.h create mode 100644 Minecraft.World/RegionFile.cpp create mode 100644 Minecraft.World/RegionFile.h create mode 100644 Minecraft.World/RegionFileCache.cpp create mode 100644 Minecraft.World/RegionFileCache.h create mode 100644 Minecraft.World/RegionHillsLayer.cpp create mode 100644 Minecraft.World/RegionHillsLayer.h create mode 100644 Minecraft.World/RemoveEntitiesPacket.cpp create mode 100644 Minecraft.World/RemoveEntitiesPacket.h create mode 100644 Minecraft.World/RemoveMobEffectPacket.cpp create mode 100644 Minecraft.World/RemoveMobEffectPacket.h create mode 100644 Minecraft.World/RepairContainer.cpp create mode 100644 Minecraft.World/RepairContainer.h create mode 100644 Minecraft.World/RepairMenu.cpp create mode 100644 Minecraft.World/RepairMenu.h create mode 100644 Minecraft.World/RepairResultSlot.cpp create mode 100644 Minecraft.World/RepairResultSlot.h create mode 100644 Minecraft.World/RespawnPacket.cpp create mode 100644 Minecraft.World/RespawnPacket.h create mode 100644 Minecraft.World/RestrictOpenDoorGoal.cpp create mode 100644 Minecraft.World/RestrictOpenDoorGoal.h create mode 100644 Minecraft.World/RestrictSunGoal.cpp create mode 100644 Minecraft.World/RestrictSunGoal.h create mode 100644 Minecraft.World/ResultContainer.cpp create mode 100644 Minecraft.World/ResultContainer.h create mode 100644 Minecraft.World/ResultSlot.cpp create mode 100644 Minecraft.World/ResultSlot.h create mode 100644 Minecraft.World/RiverBiome.h create mode 100644 Minecraft.World/RiverInitLayer.cpp create mode 100644 Minecraft.World/RiverInitLayer.h create mode 100644 Minecraft.World/RiverLayer.cpp create mode 100644 Minecraft.World/RiverLayer.h create mode 100644 Minecraft.World/RiverMixerLayer.cpp create mode 100644 Minecraft.World/RiverMixerLayer.h create mode 100644 Minecraft.World/Rotate.cpp create mode 100644 Minecraft.World/Rotate.h create mode 100644 Minecraft.World/RotateHeadPacket.cpp create mode 100644 Minecraft.World/RotateHeadPacket.h create mode 100644 Minecraft.World/SaddleItem.cpp create mode 100644 Minecraft.World/SaddleItem.h create mode 100644 Minecraft.World/SandFeature.cpp create mode 100644 Minecraft.World/SandFeature.h create mode 100644 Minecraft.World/SandStoneTile.cpp create mode 100644 Minecraft.World/SandStoneTile.h create mode 100644 Minecraft.World/Sapling.cpp create mode 100644 Minecraft.World/Sapling.h create mode 100644 Minecraft.World/SaplingTileItem.cpp create mode 100644 Minecraft.World/SaplingTileItem.h create mode 100644 Minecraft.World/SavedData.cpp create mode 100644 Minecraft.World/SavedData.h create mode 100644 Minecraft.World/SavedDataStorage.cpp create mode 100644 Minecraft.World/SavedDataStorage.h create mode 100644 Minecraft.World/Scale.cpp create mode 100644 Minecraft.World/Scale.h create mode 100644 Minecraft.World/ScatteredFeaturePieces.cpp create mode 100644 Minecraft.World/ScatteredFeaturePieces.h create mode 100644 Minecraft.World/SeedFoodItem.cpp create mode 100644 Minecraft.World/SeedFoodItem.h create mode 100644 Minecraft.World/SeedItem.cpp create mode 100644 Minecraft.World/SeedItem.h create mode 100644 Minecraft.World/Sensing.cpp create mode 100644 Minecraft.World/Sensing.h create mode 100644 Minecraft.World/ServerAuthDataPacket.h create mode 100644 Minecraft.World/ServerSettingsChangedPacket.cpp create mode 100644 Minecraft.World/ServerSettingsChangedPacket.h create mode 100644 Minecraft.World/SetCarriedItemPacket.cpp create mode 100644 Minecraft.World/SetCarriedItemPacket.h create mode 100644 Minecraft.World/SetCreativeModeSlotPacket.cpp create mode 100644 Minecraft.World/SetCreativeModeSlotPacket.h create mode 100644 Minecraft.World/SetEntityDataPacket.cpp create mode 100644 Minecraft.World/SetEntityDataPacket.h create mode 100644 Minecraft.World/SetEntityMotionPacket.cpp create mode 100644 Minecraft.World/SetEntityMotionPacket.h create mode 100644 Minecraft.World/SetEquippedItemPacket.cpp create mode 100644 Minecraft.World/SetEquippedItemPacket.h create mode 100644 Minecraft.World/SetExperiencePacket.cpp create mode 100644 Minecraft.World/SetExperiencePacket.h create mode 100644 Minecraft.World/SetHealthPacket.cpp create mode 100644 Minecraft.World/SetHealthPacket.h create mode 100644 Minecraft.World/SetRidingPacket.cpp create mode 100644 Minecraft.World/SetRidingPacket.h create mode 100644 Minecraft.World/SetSpawnPositionPacket.cpp create mode 100644 Minecraft.World/SetSpawnPositionPacket.h create mode 100644 Minecraft.World/SetTimePacket.cpp create mode 100644 Minecraft.World/SetTimePacket.h create mode 100644 Minecraft.World/ShapedRecipy.cpp create mode 100644 Minecraft.World/ShapedRecipy.h create mode 100644 Minecraft.World/ShapelessRecipy.cpp create mode 100644 Minecraft.World/ShapelessRecipy.h create mode 100644 Minecraft.World/SharedConstants.cpp create mode 100644 Minecraft.World/SharedConstants.h create mode 100644 Minecraft.World/SharedKeyPacket.h create mode 100644 Minecraft.World/ShearsItem.cpp create mode 100644 Minecraft.World/ShearsItem.h create mode 100644 Minecraft.World/Sheep.cpp create mode 100644 Minecraft.World/Sheep.h create mode 100644 Minecraft.World/ShoreLayer.cpp create mode 100644 Minecraft.World/ShoreLayer.h create mode 100644 Minecraft.World/ShortTag.h create mode 100644 Minecraft.World/ShovelItem.cpp create mode 100644 Minecraft.World/ShovelItem.h create mode 100644 Minecraft.World/SignItem.cpp create mode 100644 Minecraft.World/SignItem.h create mode 100644 Minecraft.World/SignTile.cpp create mode 100644 Minecraft.World/SignTile.h create mode 100644 Minecraft.World/SignTileEntity.cpp create mode 100644 Minecraft.World/SignTileEntity.h create mode 100644 Minecraft.World/SignUpdatePacket.cpp create mode 100644 Minecraft.World/SignUpdatePacket.h create mode 100644 Minecraft.World/Silverfish.cpp create mode 100644 Minecraft.World/Silverfish.h create mode 100644 Minecraft.World/SimpleContainer.cpp create mode 100644 Minecraft.World/SimpleContainer.h create mode 100644 Minecraft.World/SimplexNoise.cpp create mode 100644 Minecraft.World/SimplexNoise.h create mode 100644 Minecraft.World/SitGoal.cpp create mode 100644 Minecraft.World/SitGoal.h create mode 100644 Minecraft.World/Skeleton.cpp create mode 100644 Minecraft.World/Skeleton.h create mode 100644 Minecraft.World/SkullItem.cpp create mode 100644 Minecraft.World/SkullItem.h create mode 100644 Minecraft.World/SkullTile.cpp create mode 100644 Minecraft.World/SkullTile.h create mode 100644 Minecraft.World/SkullTileEntity.cpp create mode 100644 Minecraft.World/SkullTileEntity.h create mode 100644 Minecraft.World/SkyIslandDimension.cpp create mode 100644 Minecraft.World/Slime.cpp create mode 100644 Minecraft.World/Slime.h create mode 100644 Minecraft.World/Slot.cpp create mode 100644 Minecraft.World/Slot.h create mode 100644 Minecraft.World/SmallFireball.cpp create mode 100644 Minecraft.World/SmallFireball.h create mode 100644 Minecraft.World/SmoothFloat.cpp create mode 100644 Minecraft.World/SmoothFloat.h create mode 100644 Minecraft.World/SmoothLayer.cpp create mode 100644 Minecraft.World/SmoothLayer.h create mode 100644 Minecraft.World/SmoothStoneBrickTile.cpp create mode 100644 Minecraft.World/SmoothStoneBrickTile.h create mode 100644 Minecraft.World/SmoothStoneBrickTileItem.cpp create mode 100644 Minecraft.World/SmoothStoneBrickTileItem.h create mode 100644 Minecraft.World/SmoothZoomLayer.cpp create mode 100644 Minecraft.World/SmoothZoomLayer.h create mode 100644 Minecraft.World/SnowMan.cpp create mode 100644 Minecraft.World/SnowMan.h create mode 100644 Minecraft.World/SnowTile.cpp create mode 100644 Minecraft.World/SnowTile.h create mode 100644 Minecraft.World/Snowball.cpp create mode 100644 Minecraft.World/Snowball.h create mode 100644 Minecraft.World/SnowballItem.cpp create mode 100644 Minecraft.World/SnowballItem.h create mode 100644 Minecraft.World/Socket.cpp create mode 100644 Minecraft.World/Socket.h create mode 100644 Minecraft.World/SocketAddress.h create mode 100644 Minecraft.World/SoundTypes.h create mode 100644 Minecraft.World/SparseDataStorage.cpp create mode 100644 Minecraft.World/SparseDataStorage.h create mode 100644 Minecraft.World/SparseLightStorage.cpp create mode 100644 Minecraft.World/SparseLightStorage.h create mode 100644 Minecraft.World/Spider.cpp create mode 100644 Minecraft.World/Spider.h create mode 100644 Minecraft.World/SpikeFeature.cpp create mode 100644 Minecraft.World/SpikeFeature.h create mode 100644 Minecraft.World/Sponge.cpp create mode 100644 Minecraft.World/Sponge.h create mode 100644 Minecraft.World/SpringFeature.cpp create mode 100644 Minecraft.World/SpringFeature.h create mode 100644 Minecraft.World/SpringTile.cpp create mode 100644 Minecraft.World/SpringTile.h create mode 100644 Minecraft.World/SpruceFeature.cpp create mode 100644 Minecraft.World/SpruceFeature.h create mode 100644 Minecraft.World/Squid.cpp create mode 100644 Minecraft.World/Squid.h create mode 100644 Minecraft.World/StairTile.cpp create mode 100644 Minecraft.World/StairTile.h create mode 100644 Minecraft.World/Stat.cpp create mode 100644 Minecraft.World/Stat.h create mode 100644 Minecraft.World/StatFormatter.h create mode 100644 Minecraft.World/Stats.cpp create mode 100644 Minecraft.World/Stats.h create mode 100644 Minecraft.World/StemTile.cpp create mode 100644 Minecraft.World/StemTile.h create mode 100644 Minecraft.World/StoneMonsterTile.cpp create mode 100644 Minecraft.World/StoneMonsterTile.h create mode 100644 Minecraft.World/StoneMonsterTileItem.cpp create mode 100644 Minecraft.World/StoneMonsterTileItem.h create mode 100644 Minecraft.World/StoneSlabTile.cpp create mode 100644 Minecraft.World/StoneSlabTile.h create mode 100644 Minecraft.World/StoneSlabTileItem.cpp create mode 100644 Minecraft.World/StoneSlabTileItem.h create mode 100644 Minecraft.World/StoneTile.cpp create mode 100644 Minecraft.World/StoneTile.h create mode 100644 Minecraft.World/StringHelpers.cpp create mode 100644 Minecraft.World/StringHelpers.h create mode 100644 Minecraft.World/StringTag.h create mode 100644 Minecraft.World/StrongholdFeature.cpp create mode 100644 Minecraft.World/StrongholdFeature.h create mode 100644 Minecraft.World/StrongholdPieces.cpp create mode 100644 Minecraft.World/StrongholdPieces.h create mode 100644 Minecraft.World/StructureFeature.cpp create mode 100644 Minecraft.World/StructureFeature.h create mode 100644 Minecraft.World/StructurePiece.cpp create mode 100644 Minecraft.World/StructurePiece.h create mode 100644 Minecraft.World/StructureRecipies.cpp create mode 100644 Minecraft.World/StructureRecipies.h create mode 100644 Minecraft.World/StructureStart.cpp create mode 100644 Minecraft.World/StructureStart.h create mode 100644 Minecraft.World/SwampBiome.cpp create mode 100644 Minecraft.World/SwampBiome.h create mode 100644 Minecraft.World/SwampRiversLayer.cpp create mode 100644 Minecraft.World/SwampRiversLayer.h create mode 100644 Minecraft.World/SwampTreeFeature.cpp create mode 100644 Minecraft.World/SwampTreeFeature.h create mode 100644 Minecraft.World/SwellGoal.cpp create mode 100644 Minecraft.World/SwellGoal.h create mode 100644 Minecraft.World/SynchedEntityData.cpp create mode 100644 Minecraft.World/SynchedEntityData.h create mode 100644 Minecraft.World/Synth.cpp create mode 100644 Minecraft.World/Synth.h create mode 100644 Minecraft.World/System.h create mode 100644 Minecraft.World/Tag.cpp create mode 100644 Minecraft.World/Tag.h create mode 100644 Minecraft.World/TaigaBiome.cpp create mode 100644 Minecraft.World/TaigaBiome.h create mode 100644 Minecraft.World/TakeFlowerGoal.cpp create mode 100644 Minecraft.World/TakeFlowerGoal.h create mode 100644 Minecraft.World/TakeItemEntityPacket.cpp create mode 100644 Minecraft.World/TakeItemEntityPacket.h create mode 100644 Minecraft.World/TallGrass.cpp create mode 100644 Minecraft.World/TallGrass.h create mode 100644 Minecraft.World/TallGrassFeature.cpp create mode 100644 Minecraft.World/TallGrassFeature.h create mode 100644 Minecraft.World/TamableAnimal.cpp create mode 100644 Minecraft.World/TamableAnimal.h create mode 100644 Minecraft.World/TargetGoal.cpp create mode 100644 Minecraft.World/TargetGoal.h create mode 100644 Minecraft.World/TeleportEntityPacket.cpp create mode 100644 Minecraft.World/TeleportEntityPacket.h create mode 100644 Minecraft.World/TemperatureLayer.cpp create mode 100644 Minecraft.World/TemperatureLayer.h create mode 100644 Minecraft.World/TemperatureMixerLayer.cpp create mode 100644 Minecraft.World/TemperatureMixerLayer.h create mode 100644 Minecraft.World/TemptGoal.cpp create mode 100644 Minecraft.World/TemptGoal.h create mode 100644 Minecraft.World/TextureAndGeometryChangePacket.cpp create mode 100644 Minecraft.World/TextureAndGeometryChangePacket.h create mode 100644 Minecraft.World/TextureAndGeometryPacket.cpp create mode 100644 Minecraft.World/TextureAndGeometryPacket.h create mode 100644 Minecraft.World/TextureChangePacket.cpp create mode 100644 Minecraft.World/TextureChangePacket.h create mode 100644 Minecraft.World/TexturePacket.cpp create mode 100644 Minecraft.World/TexturePacket.h create mode 100644 Minecraft.World/TheEndBiome.cpp create mode 100644 Minecraft.World/TheEndBiome.h create mode 100644 Minecraft.World/TheEndBiomeDecorator.cpp create mode 100644 Minecraft.World/TheEndBiomeDecorator.h create mode 100644 Minecraft.World/TheEndDimension.cpp create mode 100644 Minecraft.World/TheEndDimension.h create mode 100644 Minecraft.World/TheEndLevelRandomLevelSource.cpp create mode 100644 Minecraft.World/TheEndLevelRandomLevelSource.h create mode 100644 Minecraft.World/TheEndPortal.cpp create mode 100644 Minecraft.World/TheEndPortal.h create mode 100644 Minecraft.World/TheEndPortalFrameTile.cpp create mode 100644 Minecraft.World/TheEndPortalFrameTile.h create mode 100644 Minecraft.World/TheEndPortalTileEntity.cpp create mode 100644 Minecraft.World/TheEndPortalTileEntity.h create mode 100644 Minecraft.World/ThinFenceTile.cpp create mode 100644 Minecraft.World/ThinFenceTile.h create mode 100644 Minecraft.World/ThornsEnchantment.cpp create mode 100644 Minecraft.World/ThornsEnchantment.h create mode 100644 Minecraft.World/ThreadName.cpp create mode 100644 Minecraft.World/ThreadName.h create mode 100644 Minecraft.World/Throwable.cpp create mode 100644 Minecraft.World/Throwable.h create mode 100644 Minecraft.World/ThrownEgg.cpp create mode 100644 Minecraft.World/ThrownEgg.h create mode 100644 Minecraft.World/ThrownEnderpearl.cpp create mode 100644 Minecraft.World/ThrownEnderpearl.h create mode 100644 Minecraft.World/ThrownExpBottle.cpp create mode 100644 Minecraft.World/ThrownExpBottle.h create mode 100644 Minecraft.World/ThrownPotion.cpp create mode 100644 Minecraft.World/ThrownPotion.h create mode 100644 Minecraft.World/TickNextTickData.cpp create mode 100644 Minecraft.World/TickNextTickData.h create mode 100644 Minecraft.World/Tile.cpp create mode 100644 Minecraft.World/Tile.h create mode 100644 Minecraft.World/TileDestructionPacket.cpp create mode 100644 Minecraft.World/TileDestructionPacket.h create mode 100644 Minecraft.World/TileEntity.cpp create mode 100644 Minecraft.World/TileEntity.h create mode 100644 Minecraft.World/TileEntityDataPacket.cpp create mode 100644 Minecraft.World/TileEntityDataPacket.h create mode 100644 Minecraft.World/TileEventData.cpp create mode 100644 Minecraft.World/TileEventData.h create mode 100644 Minecraft.World/TileEventPacket.cpp create mode 100644 Minecraft.World/TileEventPacket.h create mode 100644 Minecraft.World/TileItem.cpp create mode 100644 Minecraft.World/TileItem.h create mode 100644 Minecraft.World/TilePlanterItem.cpp create mode 100644 Minecraft.World/TilePlanterItem.h create mode 100644 Minecraft.World/TilePos.cpp create mode 100644 Minecraft.World/TilePos.h create mode 100644 Minecraft.World/TileUpdatePacket.cpp create mode 100644 Minecraft.World/TileUpdatePacket.h create mode 100644 Minecraft.World/TimeCommand.cpp create mode 100644 Minecraft.World/TimeCommand.h create mode 100644 Minecraft.World/TntTile.cpp create mode 100644 Minecraft.World/TntTile.h create mode 100644 Minecraft.World/ToggleDownfallCommand.cpp create mode 100644 Minecraft.World/ToggleDownfallCommand.h create mode 100644 Minecraft.World/ToolRecipies.cpp create mode 100644 Minecraft.World/ToolRecipies.h create mode 100644 Minecraft.World/TopSnowTile.cpp create mode 100644 Minecraft.World/TopSnowTile.h create mode 100644 Minecraft.World/TorchTile.cpp create mode 100644 Minecraft.World/TorchTile.h create mode 100644 Minecraft.World/TownFeature.h create mode 100644 Minecraft.World/TradeItemPacket.cpp create mode 100644 Minecraft.World/TradeItemPacket.h create mode 100644 Minecraft.World/TradeWithPlayerGoal.cpp create mode 100644 Minecraft.World/TradeWithPlayerGoal.h create mode 100644 Minecraft.World/TransparentTile.cpp create mode 100644 Minecraft.World/TransparentTile.h create mode 100644 Minecraft.World/TrapDoorTile.cpp create mode 100644 Minecraft.World/TrapDoorTile.h create mode 100644 Minecraft.World/TrapMenu.cpp create mode 100644 Minecraft.World/TrapMenu.h create mode 100644 Minecraft.World/TreeFeature.cpp create mode 100644 Minecraft.World/TreeFeature.h create mode 100644 Minecraft.World/TreeTile.cpp create mode 100644 Minecraft.World/TreeTile.h create mode 100644 Minecraft.World/TreeTileItem.cpp create mode 100644 Minecraft.World/TreeTileItem.h create mode 100644 Minecraft.World/TripWireSourceTile.cpp create mode 100644 Minecraft.World/TripWireSourceTile.h create mode 100644 Minecraft.World/TripWireTile.cpp create mode 100644 Minecraft.World/TripWireTile.h create mode 100644 Minecraft.World/UntouchingEnchantment.cpp create mode 100644 Minecraft.World/UntouchingEnchantment.h create mode 100644 Minecraft.World/UpdateGameRuleProgressPacket.cpp create mode 100644 Minecraft.World/UpdateGameRuleProgressPacket.h create mode 100644 Minecraft.World/UpdateMobEffectPacket.cpp create mode 100644 Minecraft.World/UpdateMobEffectPacket.h create mode 100644 Minecraft.World/UpdateProgressPacket.cpp create mode 100644 Minecraft.World/UpdateProgressPacket.h create mode 100644 Minecraft.World/UseAnim.h create mode 100644 Minecraft.World/UseItemPacket.cpp create mode 100644 Minecraft.World/UseItemPacket.h create mode 100644 Minecraft.World/Vec3.cpp create mode 100644 Minecraft.World/Vec3.h create mode 100644 Minecraft.World/Village.cpp create mode 100644 Minecraft.World/Village.h create mode 100644 Minecraft.World/VillageFeature.cpp create mode 100644 Minecraft.World/VillageFeature.h create mode 100644 Minecraft.World/VillagePieces.cpp create mode 100644 Minecraft.World/VillagePieces.h create mode 100644 Minecraft.World/VillageSiege.cpp create mode 100644 Minecraft.World/VillageSiege.h create mode 100644 Minecraft.World/Villager.cpp create mode 100644 Minecraft.World/Villager.h create mode 100644 Minecraft.World/VillagerGolem.cpp create mode 100644 Minecraft.World/VillagerGolem.h create mode 100644 Minecraft.World/Villages.cpp create mode 100644 Minecraft.World/Villages.h create mode 100644 Minecraft.World/VineTile.cpp create mode 100644 Minecraft.World/VineTile.h create mode 100644 Minecraft.World/VinesFeature.cpp create mode 100644 Minecraft.World/VinesFeature.h create mode 100644 Minecraft.World/VoronoiZoom.cpp create mode 100644 Minecraft.World/VoronoiZoom.h create mode 100644 Minecraft.World/WallTile.cpp create mode 100644 Minecraft.World/WallTile.h create mode 100644 Minecraft.World/WaterAnimal.cpp create mode 100644 Minecraft.World/WaterAnimal.h create mode 100644 Minecraft.World/WaterColor.cpp create mode 100644 Minecraft.World/WaterColor.h create mode 100644 Minecraft.World/WaterLevelChunk.cpp create mode 100644 Minecraft.World/WaterLevelChunk.h create mode 100644 Minecraft.World/WaterLilyTile.cpp create mode 100644 Minecraft.World/WaterLilyTile.h create mode 100644 Minecraft.World/WaterLilyTileItem.cpp create mode 100644 Minecraft.World/WaterLilyTileItem.h create mode 100644 Minecraft.World/WaterWorkerEnchantment.cpp create mode 100644 Minecraft.World/WaterWorkerEnchantment.h create mode 100644 Minecraft.World/WaterlilyFeature.cpp create mode 100644 Minecraft.World/WaterlilyFeature.h create mode 100644 Minecraft.World/WeaponItem.cpp create mode 100644 Minecraft.World/WeaponItem.h create mode 100644 Minecraft.World/WeaponRecipies.cpp create mode 100644 Minecraft.World/WeaponRecipies.h create mode 100644 Minecraft.World/WebMaterial.h create mode 100644 Minecraft.World/WebTile.cpp create mode 100644 Minecraft.World/WebTile.h create mode 100644 Minecraft.World/WeighedRandom.cpp create mode 100644 Minecraft.World/WeighedRandom.h create mode 100644 Minecraft.World/WeighedTreasure.cpp create mode 100644 Minecraft.World/WeighedTreasure.h create mode 100644 Minecraft.World/Wolf.cpp create mode 100644 Minecraft.World/Wolf.h create mode 100644 Minecraft.World/WoodSlabTile.cpp create mode 100644 Minecraft.World/WoodSlabTile.h create mode 100644 Minecraft.World/WoodTile.cpp create mode 100644 Minecraft.World/WoodTile.h create mode 100644 Minecraft.World/WoolCarpetTile.cpp create mode 100644 Minecraft.World/WoolCarpetTile.h create mode 100644 Minecraft.World/WorkbenchTile.cpp create mode 100644 Minecraft.World/WorkbenchTile.h create mode 100644 Minecraft.World/XZPacket.cpp create mode 100644 Minecraft.World/XZPacket.h create mode 100644 Minecraft.World/Zombie.cpp create mode 100644 Minecraft.World/Zombie.h create mode 100644 Minecraft.World/ZoneFile.cpp create mode 100644 Minecraft.World/ZoneFile.h create mode 100644 Minecraft.World/ZoneIo.cpp create mode 100644 Minecraft.World/ZoneIo.h create mode 100644 Minecraft.World/ZonedChunkStorage.cpp create mode 100644 Minecraft.World/ZonedChunkStorage.h create mode 100644 Minecraft.World/ZoomLayer.cpp create mode 100644 Minecraft.World/ZoomLayer.h create mode 100644 Minecraft.World/com.mojang.nbt.h create mode 100644 Minecraft.World/compression.cpp create mode 100644 Minecraft.World/compression.h create mode 100644 Minecraft.World/net.minecraft.commands.common.h create mode 100644 Minecraft.World/net.minecraft.commands.h create mode 100644 Minecraft.World/net.minecraft.h create mode 100644 Minecraft.World/net.minecraft.locale.h create mode 100644 Minecraft.World/net.minecraft.network.h create mode 100644 Minecraft.World/net.minecraft.network.packet.h create mode 100644 Minecraft.World/net.minecraft.stats.h create mode 100644 Minecraft.World/net.minecraft.world.ContainerListener.h create mode 100644 Minecraft.World/net.minecraft.world.damagesource.h create mode 100644 Minecraft.World/net.minecraft.world.effect.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.control.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.goal.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.goal.target.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.navigation.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.sensing.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.util.h create mode 100644 Minecraft.World/net.minecraft.world.entity.ai.village.h create mode 100644 Minecraft.World/net.minecraft.world.entity.animal.h create mode 100644 Minecraft.World/net.minecraft.world.entity.boss.enderdragon.h create mode 100644 Minecraft.World/net.minecraft.world.entity.boss.h create mode 100644 Minecraft.World/net.minecraft.world.entity.global.h create mode 100644 Minecraft.World/net.minecraft.world.entity.h create mode 100644 Minecraft.World/net.minecraft.world.entity.item.h create mode 100644 Minecraft.World/net.minecraft.world.entity.monster.h create mode 100644 Minecraft.World/net.minecraft.world.entity.npc.h create mode 100644 Minecraft.World/net.minecraft.world.entity.player.h create mode 100644 Minecraft.World/net.minecraft.world.entity.projectile.h create mode 100644 Minecraft.World/net.minecraft.world.food.h create mode 100644 Minecraft.World/net.minecraft.world.h create mode 100644 Minecraft.World/net.minecraft.world.inventory.ContainerListener.h create mode 100644 Minecraft.World/net.minecraft.world.inventory.h create mode 100644 Minecraft.World/net.minecraft.world.item.alchemy.h create mode 100644 Minecraft.World/net.minecraft.world.item.crafting.h create mode 100644 Minecraft.World/net.minecraft.world.item.enchantment.h create mode 100644 Minecraft.World/net.minecraft.world.item.h create mode 100644 Minecraft.World/net.minecraft.world.item.trading.h create mode 100644 Minecraft.World/net.minecraft.world.level.biome.h create mode 100644 Minecraft.World/net.minecraft.world.level.chunk.h create mode 100644 Minecraft.World/net.minecraft.world.level.chunk.storage.h create mode 100644 Minecraft.World/net.minecraft.world.level.dimension.h create mode 100644 Minecraft.World/net.minecraft.world.level.h create mode 100644 Minecraft.World/net.minecraft.world.level.levelgen.feature.h create mode 100644 Minecraft.World/net.minecraft.world.level.levelgen.h create mode 100644 Minecraft.World/net.minecraft.world.level.levelgen.structure.h create mode 100644 Minecraft.World/net.minecraft.world.level.levelgen.synth.h create mode 100644 Minecraft.World/net.minecraft.world.level.material.h create mode 100644 Minecraft.World/net.minecraft.world.level.newbiome.layer.h create mode 100644 Minecraft.World/net.minecraft.world.level.pathfinder.h create mode 100644 Minecraft.World/net.minecraft.world.level.saveddata.h create mode 100644 Minecraft.World/net.minecraft.world.level.storage.h create mode 100644 Minecraft.World/net.minecraft.world.level.tile.entity.h create mode 100644 Minecraft.World/net.minecraft.world.level.tile.h create mode 100644 Minecraft.World/net.minecraft.world.level.tile.piston.h create mode 100644 Minecraft.World/net.minecraft.world.phys.h create mode 100644 Minecraft.World/stdafx.cpp create mode 100644 Minecraft.World/stdafx.h create mode 100644 Minecraft.World/system.cpp create mode 100644 Minecraft.World/x64headers/extraX64.h create mode 100644 Minecraft.World/x64headers/qnet.h create mode 100644 Minecraft.World/x64headers/xmcore.h create mode 100644 Minecraft.World/x64headers/xrnm.h create mode 100644 Minecraft.World/x64headers/xsocialpost.h create mode 100644 Minecraft.World/x64headers/xuiapp.h create mode 100644 Minecraft.World/x64headers/xuiresource.h create mode 100644 MinecraftConsoles.sln diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..23e59a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,179 @@ +# =========================================== +# Build outputs +# =========================================== +x64/ +Minecraft.Client/x64/ +Minecraft.World/x64_Debug/ +Minecraft.World/x64_Release/ +ipch/ + +# =========================================== +# Visual Studio files +# =========================================== +*.sdf +*.opensdf +*.suo +*.user +*.vspscc +*.pdb +*.obj +*.pch +*.lib +*.exe +*.dll +*.tlog +*.lastbuildstate +*.log +*.idb +*.ilk +*.exp + +# =========================================== +# Archives & packaged binaries +# =========================================== +*.zip + +# =========================================== +# Copyrighted game assets (Mojang/Microsoft) +# Users must supply these from a legal copy. +# =========================================== + +# Music (Binka audio - all platforms) +Minecraft.Client/music/ +*.binka + +# Common Media - UI (SWF), Graphics (PNG), Sound (WAV), Fonts +Minecraft.Client/Common/Media/ +# Game resource textures, art, audio, etc. +Minecraft.Client/Common/res/ +Minecraft.Client/Common/DummyTexturePack/ + +# Platform-specific media directories +Minecraft.Client/DurangoMedia/ +Minecraft.Client/OrbisMedia/ +Minecraft.Client/PS3Media/ +Minecraft.Client/PSVitaMedia/ +Minecraft.Client/Windows64Media/ + +# Console package / system data +Minecraft.Client/PS3_GAME/ +Minecraft.Client/PS4_GAME/ +Minecraft.Client/sce_sys/ +Minecraft.Client/TROPDIR/ + +# Save data directories +Minecraft.Client/Windows64/GameHDD/ + +# Thumbnail / test images +*.png +# But allow source code PNG references to be noted +!Minecraft.Client/Common/Media/Graphics/.gitkeep + +# SWF UI files (Flash-based UI assets) +*.swf + +# Arc archives (packed texture/media bundles) +*.arc + +# Miles Sound System redistributables +Minecraft.Client/redist64/ +*.asi +*.flt + +# =========================================== +# Third-party / proprietary middleware +# =========================================== + +# 4J Studios proprietary libraries +**/4JLibs/ + +# Miles Sound System (RAD Game Tools) +**/Miles/ + +# Iggy / Scaleform UI middleware (RAD Game Tools) +**/Iggy/ + +# Sentient middleware +**/Sentient/ + +# =========================================== +# Console-specific SDK / platform files +# =========================================== + +# Xbox SPU tasks +**/SPU_Tasks/ + +# PS3 Edge libraries +Minecraft.Client/PS3/Edge/ +Minecraft.Client/PS3/DATA/ +Minecraft.Client/PS3/Media/ +Minecraft.Client/PS3/Passphrase/ + +# Durango (Xbox One) extras +Minecraft.Client/Durango/DLCImages/ +Minecraft.Client/Durango/Layout/ +Minecraft.Client/Durango/Sound/ +Minecraft.Client/Durango/CU/ + +# Orbis (PS4) extras +Minecraft.Client/Orbis/DLCImages/ +Minecraft.Client/Orbis/GameConfig/ + +# PSVita extras +Minecraft.Client/PSVita/app/ +Minecraft.Client/PSVita/Builds/ + +# Xbox (360) extras +Minecraft.Client/Xbox/Audio/ +Minecraft.Client/Xbox/Font/ +Minecraft.Client/Xbox/kinect/ +Minecraft.Client/Xbox/loc/ +Minecraft.Client/Xbox/ContentPackageBuild/ +Minecraft.Client/Xbox/ReleaseBuild/ +Minecraft.Client/Xbox/SubmissionBuild/ +Minecraft.Client/Xbox/TMSFiles/ +Minecraft.Client/Xbox/Cheats/ +Minecraft.Client/Xbox/Docs/ +Minecraft.Client/Xbox/Title Update/ + +# =========================================== +# Platform DLC content directories +# =========================================== +**/DLC/ + +# =========================================== +# Misc binary/compiled assets +# =========================================== +*.msscmp +*.cd +*.xap +*.bin +*.sfo +*.at9 +*.sig +*.dat +*.ico +*.rc +*.jpg +*.docx +*.xlsx +*.rtf +*.spa +*.winmd +*.alignmentchunk +*.trp +*.gameconfig + +# =========================================== +# Third-party libraries (boost, DirectX, etc.) +# =========================================== +Minecraft.Client/PS3/PS3Extras/boost_*/ +Minecraft.Client/PS3/PS3Extras/DirectX/ +Minecraft.Client/PS3/PS3Extras/HeapInspector/ + +# Static libraries and compiled packages +*.a +*.cmp + +# Sony remote storage libs +Minecraft.Client/Common/Network/Sony/ diff --git a/Minecraft.Client/AbstractContainerScreen.cpp b/Minecraft.Client/AbstractContainerScreen.cpp new file mode 100644 index 0000000..2b3e083 --- /dev/null +++ b/Minecraft.Client/AbstractContainerScreen.cpp @@ -0,0 +1,235 @@ +#include "stdafx.h" +#include "AbstractContainerScreen.h" +#include "ItemRenderer.h" +#include "MultiplayerLocalPlayer.h" +#include "Lighting.h" +#include "GameMode.h" +#include "KeyMapping.h" +#include "Options.h" +#include "..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\Minecraft.World\net.minecraft.locale.h" +#include "..\Minecraft.World\net.minecraft.world.item.h" + +ItemRenderer *AbstractContainerScreen::itemRenderer = new ItemRenderer(); + +AbstractContainerScreen::AbstractContainerScreen(AbstractContainerMenu *menu) +{ + // 4J - added initialisers + imageWidth = 176; + imageHeight = 166; + + this->menu = menu; +} + +void AbstractContainerScreen::init() +{ + Screen::init(); + minecraft->player->containerMenu = menu; +// leftPos = (width - imageWidth) / 2; +// topPos = (height - imageHeight) / 2; + +} + +void AbstractContainerScreen::render(int xm, int ym, float a) +{ + // 4J Stu - Not used +#if 0 + renderBackground(); + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + + renderBg(a); + + glPushMatrix(); + glRotatef(120, 1, 0, 0); + Lighting::turnOn(); + glPopMatrix(); + + glPushMatrix(); + glTranslatef((float)xo, (float)yo, 0); + + glColor4f(1, 1, 1, 1); + glEnable(GL_RESCALE_NORMAL); + + Slot *hoveredSlot = NULL; + + AUTO_VAR(itEnd, menu->slots->end()); + for (AUTO_VAR(it, menu->slots->begin()); it != itEnd; it++) + { + Slot *slot = *it; //menu->slots->at(i); + + renderSlot(slot); + + if (isHovering(slot, xm, ym)) + { + hoveredSlot = slot; + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + int x = slot->x; + int y = slot->y; + fillGradient(x, y, x + 16, y + 16, 0x80ffffff, 0x80ffffff); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + } + } + + shared_ptr inventory = minecraft->player->inventory; + if (inventory->getCarried() != NULL) + { + glTranslatef(0, 0, 32); + // Slot old = carriedSlot; + // carriedSlot = null; + itemRenderer->renderGuiItem(font, minecraft->textures, inventory->getCarried(), xm - xo - 8, ym - yo - 8); + itemRenderer->renderGuiItemDecorations(font, minecraft->textures, inventory->getCarried(), xm - xo - 8, ym - yo - 8); + // carriedSlot = old; + } + glDisable(GL_RESCALE_NORMAL); + Lighting::turnOff(); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + renderLabels(); + + if (inventory->getCarried() == NULL && hoveredSlot != NULL && hoveredSlot->hasItem()) + { + + wstring elementName = trimString(Language::getInstance()->getElementName(hoveredSlot->getItem()->getDescriptionId())); + + if (elementName.length() > 0) + { + int x = xm - xo + 12; + int y = ym - yo - 12; + int width = font->width(elementName); + fillGradient(x - 3, y - 3, x + width + 3, y + 8 + 3, 0xc0000000, 0xc0000000); + + font->drawShadow(elementName, x, y, 0xffffffff); + } + + } + + glPopMatrix(); + + Screen::render(xm, ym, a); + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); +#endif +} + +void AbstractContainerScreen::renderLabels() +{ +} + +void AbstractContainerScreen::renderSlot(Slot *slot) +{ + // 4J Unused +#if 0 + int x = slot->x; + int y = slot->y; + shared_ptr item = slot->getItem(); + + if (item == NULL) + { + int icon = slot->getNoItemIcon(); + if (icon >= 0) + { + glDisable(GL_LIGHTING); + minecraft->textures->bind(minecraft->textures->loadTexture(TN_GUI_ITEMS));//L"/gui/items.png")); + blit(x, y, icon % 16 * 16, icon / 16 * 16, 16, 16); + glEnable(GL_LIGHTING); + return; + } + } + + itemRenderer->renderGuiItem(font, minecraft->textures, item, x, y); + itemRenderer->renderGuiItemDecorations(font, minecraft->textures, item, x, y); +#endif +} + +Slot *AbstractContainerScreen::findSlot(int x, int y) +{ + AUTO_VAR(itEnd, menu->slots->end()); + for (AUTO_VAR(it, menu->slots->begin()); it != itEnd; it++) + { + Slot *slot = *it; //menu->slots->at(i); + if (isHovering(slot, x, y)) return slot; + } + return NULL; +} + +bool AbstractContainerScreen::isHovering(Slot *slot, int xm, int ym) +{ + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + xm -= xo; + ym -= yo; + + return xm >= slot->x - 1 && xm < slot->x + 16 + 1 && ym >= slot->y - 1 && ym < slot->y + 16 + 1; + +} + +void AbstractContainerScreen::mouseClicked(int x, int y, int buttonNum) +{ + Screen::mouseClicked(x, y, buttonNum); + if (buttonNum == 0 || buttonNum == 1) + { + Slot *slot = findSlot(x, y); + + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + bool clickedOutside = (x < xo || y < yo || x >= xo + imageWidth || y >= yo + imageHeight); + + int slotId = -1; + if (slot != NULL) slotId = slot->index; + + if (clickedOutside) + { + slotId = AbstractContainerMenu::CLICKED_OUTSIDE; + } + + if (slotId != -1) + { + bool quickKey = slotId != AbstractContainerMenu::CLICKED_OUTSIDE && (Keyboard::isKeyDown(Keyboard::KEY_LSHIFT) || Keyboard::isKeyDown(Keyboard::KEY_RSHIFT)); + minecraft->gameMode->handleInventoryMouseClick(menu->containerId, slotId, buttonNum, quickKey, minecraft->player); + } + } + +} + +void AbstractContainerScreen::mouseReleased(int x, int y, int buttonNum) +{ + if (buttonNum == 0) + { + } +} + +void AbstractContainerScreen::keyPressed(wchar_t eventCharacter, int eventKey) +{ + if (eventKey == Keyboard::KEY_ESCAPE || eventKey == minecraft->options->keyBuild->key) + { + minecraft->player->closeContainer(); + } +} + +void AbstractContainerScreen::removed() +{ + if (minecraft->player == NULL) return; +} + +void AbstractContainerScreen::slotsChanged(shared_ptr container) +{ +} + +bool AbstractContainerScreen::isPauseScreen() +{ + return false; +} + +void AbstractContainerScreen::tick() +{ + Screen::tick(); + if (!minecraft->player->isAlive() || minecraft->player->removed) minecraft->player->closeContainer(); + +} \ No newline at end of file diff --git a/Minecraft.Client/AbstractContainerScreen.h b/Minecraft.Client/AbstractContainerScreen.h new file mode 100644 index 0000000..2ba9cdc --- /dev/null +++ b/Minecraft.Client/AbstractContainerScreen.h @@ -0,0 +1,38 @@ +#pragma once +#include "Screen.h" +class ItemRenderer; +class AbstractContainerMenu; +class Slot; +class Container; + +class AbstractContainerScreen : public Screen +{ +private: + static ItemRenderer *itemRenderer; +protected: + int imageWidth; + int imageHeight; + //int leftPos, topPos; +public: + AbstractContainerMenu *menu; + + AbstractContainerScreen(AbstractContainerMenu *menu); + virtual void init(); + virtual void render(int xm, int ym, float a); +protected: + virtual void renderLabels(); + virtual void renderBg(float a) = 0; +private: + virtual void renderSlot(Slot *slot); + virtual Slot *findSlot(int x, int y); + virtual bool isHovering(Slot *slot, int xm, int ym); +protected: + virtual void mouseClicked(int x, int y, int buttonNum); + virtual void mouseReleased(int x, int y, int buttonNum); + virtual void keyPressed(wchar_t eventCharacter, int eventKey); +public: + virtual void removed(); + virtual void slotsChanged(shared_ptr container); + virtual bool isPauseScreen(); + virtual void tick(); +}; \ No newline at end of file diff --git a/Minecraft.Client/AbstractTexturePack.cpp b/Minecraft.Client/AbstractTexturePack.cpp new file mode 100644 index 0000000..a4eb7f0 --- /dev/null +++ b/Minecraft.Client/AbstractTexturePack.cpp @@ -0,0 +1,399 @@ +#include "stdafx.h" +#include "Textures.h" +#include "AbstractTexturePack.h" +#include "..\Minecraft.World\InputOutputStream.h" +#include "..\Minecraft.World\StringHelpers.h" + +AbstractTexturePack::AbstractTexturePack(DWORD id, File *file, const wstring &name, TexturePack *fallback) : id(id), name(name) +{ + // 4J init + textureId = -1; + m_colourTable = NULL; + + + this->file = file; + this->fallback = fallback; + + m_iconData = NULL; + m_iconSize = 0; + + m_comparisonData = NULL; + m_comparisonSize = 0; + + // 4J Stu - These calls need to be in the most derived version of the class + //loadIcon(); + //loadDescription(); +} + +wstring AbstractTexturePack::trim(wstring line) +{ + if (!line.empty() && line.length() > 34) + { + line = line.substr(0, 34); + } + return line; +} + +void AbstractTexturePack::loadIcon() +{ +#ifdef _XBOX + // 4J Stu - Temporary only + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + swprintf(szResourceLocator, LOCATOR_SIZE ,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/TexturePackIcon.png"); + + UINT size = 0; + HRESULT hr = XuiResourceLoadAllNoLoc(szResourceLocator, &m_iconData, &size); + m_iconSize = size; +#endif +} + +void AbstractTexturePack::loadComparison() +{ +#ifdef _XBOX + // 4J Stu - Temporary only + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + swprintf(szResourceLocator, LOCATOR_SIZE ,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/Graphics/DefaultPack_Comparison.png"); + + UINT size = 0; + HRESULT hr = XuiResourceLoadAllNoLoc(szResourceLocator, &m_comparisonData, &size); + m_comparisonSize = size; +#endif +} + +void AbstractTexturePack::loadDescription() +{ + // 4J Unused currently +#if 0 + InputStream *inputStream = NULL; + BufferedReader *br = NULL; + //try { + inputStream = getResourceImplementation(L"/pack.txt"); + br = new BufferedReader(new InputStreamReader(inputStream)); + desc1 = trim(br->readLine()); + desc2 = trim(br->readLine()); + //} catch (IOException ignored) { + //} finally { + // TODO [EB]: use IOUtils.closeSilently() + // try { + if (br != NULL) + { + br->close(); + delete br; + } + if (inputStream != NULL) + { + inputStream->close(); + delete inputStream; + } + // } catch (IOException ignored) { + // } + //} +#endif +} + +void AbstractTexturePack::loadName() +{ +} + +InputStream *AbstractTexturePack::getResource(const wstring &name, bool allowFallback) //throws IOException +{ + app.DebugPrintf("texture - %ls\n",name.c_str()); + InputStream *is = getResourceImplementation(name); + if (is == NULL && fallback != NULL && allowFallback) + { + is = fallback->getResource(name, true); + } + + return is; +} + +// 4J Currently removed due to override in TexturePack class +//InputStream *AbstractTexturePack::getResource(const wstring &name) //throws IOException +//{ +// return getResource(name, true); +//} + +void AbstractTexturePack::unload(Textures *textures) +{ + if (iconImage != NULL && textureId != -1) + { + textures->releaseTexture(textureId); + } +} + +void AbstractTexturePack::load(Textures *textures) +{ + if (iconImage != NULL) + { + if (textureId == -1) + { + textureId = textures->getTexture(iconImage); + } + glBindTexture(GL_TEXTURE_2D, textureId); + textures->clearLastBoundId(); + } + else + { + // 4J Stu - Don't do this + //textures->bindTexture(L"/gui/unknown_pack.png"); + } +} + +bool AbstractTexturePack::hasFile(const wstring &name, bool allowFallback) +{ + bool hasFile = this->hasFile(name); + + return !hasFile && (allowFallback && fallback != NULL) ? fallback->hasFile(name, allowFallback) : hasFile; +} + +DWORD AbstractTexturePack::getId() +{ + return id; +} + +wstring AbstractTexturePack::getName() +{ + return texname; +} + +wstring AbstractTexturePack::getWorldName() +{ + return m_wsWorldName; +} + +wstring AbstractTexturePack::getDesc1() +{ + return desc1; +} + +wstring AbstractTexturePack::getDesc2() +{ + return desc2; +} + +wstring AbstractTexturePack::getAnimationString(const wstring &textureName, const wstring &path, bool allowFallback) +{ + return getAnimationString(textureName, path); +} + +wstring AbstractTexturePack::getAnimationString(const wstring &textureName, const wstring &path) +{ + wstring animationDefinitionFile = textureName + L".txt"; + + bool requiresFallback = !hasFile(L"\\" + textureName + L".png", false); + + InputStream *fileStream = getResource(L"\\" + path + animationDefinitionFile, requiresFallback); + + //Minecraft::getInstance()->getLogger().info("Found animation info for: " + animationDefinitionFile); +#ifndef _CONTENT_PACKAGE + wprintf(L"Found animation info for: %ls\n", animationDefinitionFile.c_str() ); +#endif + InputStreamReader isr(fileStream); + BufferedReader br(&isr); + + wstring result = L""; + + wstring line = br.readLine(); + while (!line.empty()) + { + line = trimString(line); + if (line.length() > 0) + { + result.append(L","); + result.append(line); + } + line = br.readLine(); + } + delete fileStream; + + return result; +} + +BufferedImage *AbstractTexturePack::getImageResource(const wstring& File, bool filenameHasExtension /*= false*/, bool bTitleUpdateTexture /*=false*/, const wstring &drive /*=L""*/) +{ + const char *pchTexture=wstringtofilename(File); + app.DebugPrintf("AbstractTexturePack::getImageResource - %s, drive is %s\n",pchTexture, wstringtofilename(drive)); + + return new BufferedImage(TexturePack::getResource(L"/" + File),filenameHasExtension,bTitleUpdateTexture,drive); +} + +void AbstractTexturePack::loadDefaultUI() +{ +#ifdef _XBOX + // load from the .xzp file + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + + // Load new skin + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + swprintf(szResourceLocator, LOCATOR_SIZE,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/skin_Minecraft.xur"); + + XuiFreeVisuals(L""); + app.LoadSkin(szResourceLocator,NULL);//L"TexturePack"); + //CXuiSceneBase::GetInstance()->SetVisualPrefix(L"TexturePack"); + CXuiSceneBase::GetInstance()->SkinChanged(CXuiSceneBase::GetInstance()->m_hObj); +#else + ui.ReloadSkin(); +#endif +} + +void AbstractTexturePack::loadColourTable() +{ + loadDefaultColourTable(); + loadDefaultHTMLColourTable(); +} + +void AbstractTexturePack::loadDefaultColourTable() +{ + // Load the file + File coloursFile(AbstractTexturePack::getPath(true).append(L"res/colours.col")); + + if(coloursFile.exists()) + { + DWORD dwLength = coloursFile.length(); + byteArray data(dwLength); + + FileInputStream fis(coloursFile); + fis.read(data,0,dwLength); + fis.close(); + if(m_colourTable != NULL) delete m_colourTable; + m_colourTable = new ColourTable(data.data, dwLength); + + delete [] data.data; + } + else + { + app.DebugPrintf("Failed to load the default colours table\n"); + app.FatalLoadError(); + } +} + +void AbstractTexturePack::loadDefaultHTMLColourTable() +{ +#ifdef _XBOX + // load from the .xzp file + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + // Try and load the HTMLColours.col based off the common XML first, before the deprecated xuiscene_colourtable + wsprintfW(szResourceLocator,L"section://%X,%s#%s",c_ModuleHandle,L"media", L"media/HTMLColours.col"); + BYTE *data; + UINT dataLength; + if(XuiResourceLoadAll(szResourceLocator, &data, &dataLength) == S_OK) + { + m_colourTable->loadColoursFromData(data,dataLength); + + XuiFree(data); + } + else + { + wsprintfW(szResourceLocator,L"section://%X,%s#%s",c_ModuleHandle,L"media", L"media/"); + HXUIOBJ hScene; + HRESULT hr = XuiSceneCreate(szResourceLocator,L"xuiscene_colourtable.xur", NULL, &hScene); + + if(HRESULT_SUCCEEDED(hr)) + { + loadHTMLColourTableFromXuiScene(hScene); + } + } +#else + if(app.hasArchiveFile(L"HTMLColours.col")) + { + byteArray textColours = app.getArchiveFile(L"HTMLColours.col"); + m_colourTable->loadColoursFromData(textColours.data,textColours.length); + + delete [] textColours.data; + } +#endif +} + +#ifdef _XBOX +void AbstractTexturePack::loadHTMLColourTableFromXuiScene(HXUIOBJ hObj) +{ + HXUIOBJ child; + HRESULT hr = XuiElementGetFirstChild(hObj, &child); + + while(HRESULT_SUCCEEDED(hr) && child != NULL) + { + LPCWSTR childName; + XuiElementGetId(child,&childName); + m_colourTable->setColour(childName,XuiTextElementGetText(child)); + + //eMinecraftTextColours colourIndex = eTextColor_NONE; + //for(int i = 0; i < (int)eTextColor_MAX; i++) + //{ + // if(wcscmp(HTMLColourTableElements[i],childName)==0) + // { + // colourIndex = (eMinecraftTextColours)i; + // break; + // } + //} + + //LPCWSTR stringValue = XuiTextElementGetText(child); + + //m_htmlColourTable[colourIndex] = XuiTextElementGetText(child); + + hr = XuiElementGetNext(child, &child); + } +} +#endif + +void AbstractTexturePack::loadUI() +{ + loadColourTable(); + +#ifdef _XBOX + CXuiSceneBase::GetInstance()->SkinChanged(CXuiSceneBase::GetInstance()->m_hObj); +#endif +} + +void AbstractTexturePack::unloadUI() +{ + // Do nothing +} + +wstring AbstractTexturePack::getXuiRootPath() +{ + const ULONG_PTR c_ModuleHandle = (ULONG_PTR)GetModuleHandle(NULL); + + // Load new skin + const DWORD LOCATOR_SIZE = 256; // Use this to allocate space to hold a ResourceLocator string + WCHAR szResourceLocator[ LOCATOR_SIZE ]; + + swprintf(szResourceLocator, LOCATOR_SIZE,L"section://%X,%ls#%ls",c_ModuleHandle,L"media", L"media/"); + return szResourceLocator; +} + +PBYTE AbstractTexturePack::getPackIcon(DWORD &dwImageBytes) +{ + if(m_iconSize == 0 || m_iconData == NULL) loadIcon(); + dwImageBytes = m_iconSize; + return m_iconData; +} + +PBYTE AbstractTexturePack::getPackComparison(DWORD &dwImageBytes) +{ + if(m_comparisonSize == 0 || m_comparisonData == NULL) loadComparison(); + + dwImageBytes = m_comparisonSize; + return m_comparisonData; +} + +unsigned int AbstractTexturePack::getDLCParentPackId() +{ + return 0; +} + +unsigned char AbstractTexturePack::getDLCSubPackId() +{ + return 0; +} \ No newline at end of file diff --git a/Minecraft.Client/AbstractTexturePack.h b/Minecraft.Client/AbstractTexturePack.h new file mode 100644 index 0000000..e6410c1 --- /dev/null +++ b/Minecraft.Client/AbstractTexturePack.h @@ -0,0 +1,93 @@ +#pragma once +using namespace std; + +#include "TexturePack.h" + +class BufferedImage; + +class AbstractTexturePack : public TexturePack +{ +private: + const DWORD id; + const wstring name; + +protected: + File *file; + wstring texname; + wstring m_wsWorldName; + + wstring desc1; + wstring desc2; + + PBYTE m_iconData; + DWORD m_iconSize; + + PBYTE m_comparisonData; + DWORD m_comparisonSize; + + TexturePack *fallback; + + ColourTable *m_colourTable; + +protected: + BufferedImage *iconImage; + +private: + int textureId; + +protected: + AbstractTexturePack(DWORD id, File *file, const wstring &name, TexturePack *fallback); + +private: + static wstring trim(wstring line); + +protected: + virtual void loadIcon(); + virtual void loadComparison(); + virtual void loadDescription(); + virtual void loadName(); + +public: + virtual InputStream *getResource(const wstring &name, bool allowFallback); //throws IOException + // 4J Removed do to current override in TexturePack class + //virtual InputStream *getResource(const wstring &name); //throws IOException + virtual DLCPack * getDLCPack() =0; + + +protected: + virtual InputStream *getResourceImplementation(const wstring &name) = 0; // throws IOException; +public: + virtual void unload(Textures *textures); + virtual void load(Textures *textures); + virtual bool hasFile(const wstring &name, bool allowFallback); + virtual bool hasFile(const wstring &name) = 0; + virtual DWORD getId(); + virtual wstring getName(); + virtual wstring getDesc1(); + virtual wstring getDesc2(); + virtual wstring getWorldName(); + + virtual wstring getAnimationString(const wstring &textureName, const wstring &path, bool allowFallback); + +protected: + virtual wstring getAnimationString(const wstring &textureName, const wstring &path); + void loadDefaultUI(); + void loadDefaultColourTable(); + void loadDefaultHTMLColourTable(); +#ifdef _XBOX + void loadHTMLColourTableFromXuiScene(HXUIOBJ hObj); +#endif + +public: + virtual BufferedImage *getImageResource(const wstring& File, bool filenameHasExtension = false, bool bTitleUpdateTexture=false, const wstring &drive =L""); + virtual void loadColourTable(); + virtual void loadUI(); + virtual void unloadUI(); + virtual wstring getXuiRootPath(); + virtual PBYTE getPackIcon(DWORD &dwImageBytes); + virtual PBYTE getPackComparison(DWORD &dwImageBytes); + virtual unsigned int getDLCParentPackId(); + virtual unsigned char getDLCSubPackId(); + virtual ColourTable *getColourTable() { return m_colourTable; } + virtual ArchiveFile *getArchiveFile() { return NULL; } +}; diff --git a/Minecraft.Client/AchievementPopup.cpp b/Minecraft.Client/AchievementPopup.cpp new file mode 100644 index 0000000..04f822a --- /dev/null +++ b/Minecraft.Client/AchievementPopup.cpp @@ -0,0 +1,151 @@ +#include "stdafx.h" +#include "AchievementPopup.h" +#include "ItemRenderer.h" +#include "Font.h" +#include "Textures.h" +#include "Lighting.h" +#include "..\Minecraft.World\System.h" +#include "..\Minecraft.World\net.minecraft.locale.h" +#include "..\Minecraft.World\net.minecraft.stats.h" +#include "..\Minecraft.World\SharedConstants.h" + +AchievementPopup::AchievementPopup(Minecraft *mc) +{ + // 4J - added initialisers + width = 0; + height = 0; + ach = NULL; + startTime = 0; + isHelper = false; + + this->mc = mc; + ir = new ItemRenderer(); +} + +void AchievementPopup::popup(Achievement *ach) +{ + title = I18n::get(L"achievement.get"); + desc = ach->name; + startTime = System::currentTimeMillis(); + this->ach = ach; + isHelper = false; +} + +void AchievementPopup::permanent(Achievement *ach) +{ + title = ach->name; + desc = ach->getDescription(); + + startTime = System::currentTimeMillis() - 2500; + this->ach = ach; + isHelper = true; +} + +void AchievementPopup::prepareWindow() +{ + glViewport(0, 0, mc->width, mc->height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + + this->width = mc->width; + this->height = mc->height; + + ScreenSizeCalculator ssc(mc->options, mc->width, mc->height); + width = ssc.getWidth(); + height = ssc.getHeight(); + + glClear(GL_DEPTH_BUFFER_BIT); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, (float)width, (float)height, 0, 1000, 3000); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0, 0, -2000); + +} + +void AchievementPopup::render() +{ +// 4J Unused +#if 0 + if (Minecraft::warezTime > 0) + { + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + Lighting::turnOff(); + prepareWindow(); + + wstring title = L"Minecraft " + SharedConstants::VERSION_STRING + L" Unlicensed Copy :("; + wstring msg1 = L"(Or logged in from another location)"; + wstring msg2 = L"Purchase at minecraft.net"; + + mc->font->drawShadow(title, 2, 2 + 9 * 0, 0xffffff); + mc->font->drawShadow(msg1, 2, 2 + 9 * 1, 0xffffff); + mc->font->drawShadow(msg2, 2, 2 + 9 * 2, 0xffffff); + + glDepthMask(true); + glEnable(GL_DEPTH_TEST); + } + if (ach == NULL || startTime == 0) return; + + double time = (System::currentTimeMillis() - startTime) / 3000.0; + if (isHelper) + { + } + else if (!isHelper && (time < 0 || time > 1)) + { + startTime = 0; + return; + } + + + prepareWindow(); + glDisable(GL_DEPTH_TEST); + glDepthMask(false); + + double yo = time * 2; + if (yo > 1) yo = 2 - yo; + yo = yo * 4; + yo = 1 - yo; + if (yo < 0) yo = 0; + yo = yo * yo; + yo = yo * yo; + + int xx = width - 160; + int yy = 0 - (int) (yo * 36); + int tex = mc->textures->loadTexture(L"/achievement/bg.png"); + glColor4f(1, 1, 1, 1); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tex); + glDisable(GL_LIGHTING); + + blit(xx, yy, 96, 202, 160, 32); + + if (isHelper) + { + mc->font->drawWordWrap(desc, xx + 30, yy + 7, 120, 0xffffffff); + } + else + { + mc->font->draw(title, xx + 30, yy + 7, 0xffffff00); + mc->font->draw(desc, xx + 30, yy + 18, 0xffffffff); + } + + glPushMatrix(); + glRotatef(180, 1, 0, 0); + Lighting::turnOn(); + glPopMatrix(); + glDisable(GL_LIGHTING); + glEnable(GL_RESCALE_NORMAL); + glEnable(GL_COLOR_MATERIAL); + + glEnable(GL_LIGHTING); + ir->renderGuiItem(mc->font, mc->textures, ach->icon, xx + 8, yy + 8); + glDisable(GL_LIGHTING); + + glDepthMask(true); + glEnable(GL_DEPTH_TEST); +#endif +} \ No newline at end of file diff --git a/Minecraft.Client/AchievementPopup.h b/Minecraft.Client/AchievementPopup.h new file mode 100644 index 0000000..3085dc6 --- /dev/null +++ b/Minecraft.Client/AchievementPopup.h @@ -0,0 +1,28 @@ +#pragma once +#include "GuiComponent.h" +class Achievement; +class ItemRenderer; +using namespace std; + +class AchievementPopup : public GuiComponent +{ +private: + Minecraft *mc; + int width, height; + + wstring title; + wstring desc; + Achievement *ach; + __int64 startTime; + ItemRenderer *ir; + bool isHelper; + +public: + AchievementPopup(Minecraft *mc); + void popup(Achievement *ach); + void permanent(Achievement *ach); +private: + void prepareWindow(); +public: + void render(); +}; \ No newline at end of file diff --git a/Minecraft.Client/AchievementScreen.cpp b/Minecraft.Client/AchievementScreen.cpp new file mode 100644 index 0000000..26f2032 --- /dev/null +++ b/Minecraft.Client/AchievementScreen.cpp @@ -0,0 +1,426 @@ +#include "stdafx.h" +#include "AchievementScreen.h" +#include "SmallButton.h" +#include "Options.h" +#include "KeyMapping.h" +#include "Font.h" +#include "Lighting.h" +#include "Textures.h" +#include "StatsCounter.h" +#include "ItemRenderer.h" +#include "..\Minecraft.World\System.h" +#include "..\Minecraft.World\net.minecraft.locale.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\Minecraft.World\JavaMath.h" + + + +AchievementScreen::AchievementScreen(StatsCounter *statsCounter) +{ + // 4J - added initialisers + imageWidth = 256; + imageHeight = 202; + xLastScroll = 0; + yLastScroll = 0; + scrolling = 0; + + // 4J - TODO - investigate - these were static final ints before, but based on members of Achievements which + // aren't final Or actually initialised + xMin = Achievements::xMin * ACHIEVEMENT_COORD_SCALE - BIGMAP_WIDTH / 2; + yMin = Achievements::yMin * ACHIEVEMENT_COORD_SCALE - BIGMAP_WIDTH / 2; + xMax = Achievements::xMax * ACHIEVEMENT_COORD_SCALE - BIGMAP_HEIGHT / 2; + yMax = Achievements::yMax * ACHIEVEMENT_COORD_SCALE - BIGMAP_HEIGHT / 2; + + this->statsCounter = statsCounter; + int wBigMap = 141; + int hBigMap = 141; + + xScrollO = xScrollP = xScrollTarget = Achievements::openInventory->x * ACHIEVEMENT_COORD_SCALE - wBigMap / 2 - 12; + yScrollO = yScrollP = yScrollTarget = Achievements::openInventory->y * ACHIEVEMENT_COORD_SCALE - hBigMap / 2; + +} + +void AchievementScreen::init() +{ + buttons.clear(); +// buttons.add(new SmallButton(0, width / 2 - 80 - 24, height / 2 + 74, 110, 20, I18n.get("gui.achievements"))); + buttons.push_back(new SmallButton(1, width / 2 + 24, height / 2 + 74, 80, 20, I18n::get(L"gui.done"))); + +} + +void AchievementScreen::buttonClicked(Button *button) +{ + if (button->id == 1) + { + minecraft->setScreen(NULL); +// minecraft->grabMouse(); // 4J removed + } + Screen::buttonClicked(button); +} + +void AchievementScreen::keyPressed(char eventCharacter, int eventKey) +{ + if (eventKey == minecraft->options->keyBuild->key) + { + minecraft->setScreen(NULL); +// minecraft->grabMouse(); // 4J removed + } + else + { + Screen::keyPressed(eventCharacter, eventKey); + } +} + +void AchievementScreen::render(int mouseX, int mouseY, float a) +{ + if (Mouse::isButtonDown(0)) + { + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + + int xBigMap = xo + 8; + int yBigMap = yo + 17; + + if (scrolling == 0 || scrolling == 1) + { + if (mouseX >= xBigMap && mouseX < xBigMap + BIGMAP_WIDTH && mouseY >= yBigMap && mouseY < yBigMap + BIGMAP_HEIGHT) + { + if (scrolling == 0) + { + scrolling = 1; + } + else + { + xScrollP -= mouseX - xLastScroll; + yScrollP -= mouseY - yLastScroll; + xScrollTarget = xScrollO = xScrollP; + yScrollTarget = yScrollO = yScrollP; + } + xLastScroll = mouseX; + yLastScroll = mouseY; + } + } + + if (xScrollTarget < xMin) xScrollTarget = xMin; + if (yScrollTarget < yMin) yScrollTarget = yMin; + if (xScrollTarget >= xMax) xScrollTarget = xMax - 1; + if (yScrollTarget >= yMax) yScrollTarget = yMax - 1; + } + else + { + scrolling = 0; + } + + renderBackground(); + + renderBg(mouseX, mouseY, a); + + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + + renderLabels(); + + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + +} + +void AchievementScreen::tick() +{ + xScrollO = xScrollP; + yScrollO = yScrollP; + + double xd = (xScrollTarget - xScrollP); + double yd = (yScrollTarget - yScrollP); + if (xd * xd + yd * yd < 4) + { + xScrollP += xd; + yScrollP += yd; + } + else + { + xScrollP += xd * 0.85; + yScrollP += yd * 0.85; + } +} + +void AchievementScreen::renderLabels() +{ + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + font->draw(L"Achievements", xo + 15, yo + 5, 0x404040); + +// font.draw(xScrollP + ", " + yScrollP, xo + 5, yo + 5 + BIGMAP_HEIGHT + 18, 0x404040); +// font.drawWordWrap("Ride a pig off a cliff.", xo + 5, yo + 5 + BIGMAP_HEIGHT + 16, BIGMAP_WIDTH, 0x404040); + +} + +void AchievementScreen::renderBg(int xm, int ym, float a) +{ + // 4J Unused +#if 0 + int xScroll = Mth::floor(xScrollO + (xScrollP - xScrollO) * a); + int yScroll = Mth::floor(yScrollO + (yScrollP - yScrollO) * a); + + if (xScroll < xMin) xScroll = xMin; + if (yScroll < yMin) yScroll = yMin; + if (xScroll >= xMax) xScroll = xMax - 1; + if (yScroll >= yMax) yScroll = yMax - 1; + + + int terrainTex = minecraft->textures->loadTexture(L"/terrain.png"); + int tex = minecraft->textures->loadTexture(L"/achievement/bg.png"); + + int xo = (width - imageWidth) / 2; + int yo = (height - imageHeight) / 2; + + int xBigMap = xo + BIGMAP_X; + int yBigMap = yo + BIGMAP_Y; + + blitOffset = 0; +// glDisable(GL_DEPTH_TEST); + glDepthFunc(GL_GEQUAL); + glPushMatrix(); + glTranslatef(0, 0, -200); + + { + glEnable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + glEnable(GL_RESCALE_NORMAL); + glEnable(GL_COLOR_MATERIAL); + + minecraft->textures->bind(terrainTex); + + int leftTile = (xScroll + EDGE_VALUE_X) >> 4; + int topTile = (yScroll + EDGE_VALUE_Y) >> 4; + int xMod = (xScroll + EDGE_VALUE_X) % 16; + int yMod = (yScroll + EDGE_VALUE_Y) % 16; + + const int rockLevel = (Achievements::ACHIEVEMENT_HEIGHT_POSITION * 4) / 10; + const int coalLevel = (Achievements::ACHIEVEMENT_HEIGHT_POSITION * 7) / 10; + const int ironLevel = (Achievements::ACHIEVEMENT_HEIGHT_POSITION * 9) / 10; + const int diamondLevel = (Achievements::ACHIEVEMENT_HEIGHT_POSITION * 19) / 10; + const int bedrockLevel = (Achievements::ACHIEVEMENT_HEIGHT_POSITION * 31) / 10; + + Random *random = new Random(); + + for (int tileY = 0; (tileY * 16) - yMod < BIGMAP_HEIGHT; tileY++) + { + + float amount = .6f - (float) (topTile + tileY) / (float) (Achievements::ACHIEVEMENT_HEIGHT_POSITION * 2 + 1) * .3f; + glColor4f(amount, amount, amount, 1); + + for (int tileX = 0; (tileX * 16) - xMod < BIGMAP_WIDTH; tileX++) + { + + random->setSeed(1234 + leftTile + tileX); + random->nextInt(); + int heightValue = random->nextInt(1 + topTile + tileY) + (topTile + tileY) / 2; + int tileType = Tile::sand->tex; + + if (heightValue > bedrockLevel || (topTile + tileY) == MAX_BG_TILE_Y) + { + tileType = Tile::unbreakable->tex; + } + else if (heightValue == diamondLevel) + { + if (random->nextInt(2) == 0) + { + tileType = Tile::diamondOre->tex; + } + else + { + tileType = Tile::redStoneOre->tex; + } + } + else if (heightValue == ironLevel) + { + tileType = Tile::ironOre->tex; + } + else if (heightValue == coalLevel) + { + tileType = Tile::coalOre->tex; + } + else if (heightValue > rockLevel) + { + tileType = Tile::rock->tex; + } + else if (heightValue > 0) + { + tileType = Tile::dirt->tex; + } + + this->blit(xBigMap + tileX * 16 - xMod, yBigMap + tileY * 16 - yMod, (tileType % 16) << 4, (tileType >> 4) << 4, 16, 16); + } + } + + } + glEnable(GL_DEPTH_TEST); + + + glDepthFunc(GL_LEQUAL); + + glDisable(GL_TEXTURE_2D); + + AUTO_VAR(itEnd, Achievements::achievements->end()); + for (AUTO_VAR(it, Achievements::achievements->begin()); it != itEnd; it++) + { + Achievement *ach = *it; //Achievements::achievements->at(i); + if (ach->requires == NULL) continue; + + int x1 = ach->x * ACHIEVEMENT_COORD_SCALE - (int) xScroll + 11 + xBigMap; + int y1 = ach->y * ACHIEVEMENT_COORD_SCALE - (int) yScroll + 11 + yBigMap; + + int x2 = ach->requires->x * ACHIEVEMENT_COORD_SCALE - (int) xScroll + 11 + xBigMap; + int y2 = ach->requires->y * ACHIEVEMENT_COORD_SCALE - (int) yScroll + 11 + yBigMap; + + int color = 0; + + bool taken = statsCounter->hasTaken(ach); + bool canTake = statsCounter->canTake(ach); + + int alph = (int) (sin(System::currentTimeMillis() % 600 / 600.0 * PI * 2) > 0.6 ? 255 : 130); + if (taken) color = 0xff707070; + else if (canTake) color = 0x00ff00 + (alph << 24); + else color = 0xff000000; + + hLine(x1, x2, y1, color); + vLine(x2, y1, y2, color); + } + + Achievement *hoveredAchievement = NULL; + ItemRenderer *ir = new ItemRenderer(); + + glPushMatrix(); + glRotatef(180, 1, 0, 0); + Lighting::turnOn(); + glPopMatrix(); + glDisable(GL_LIGHTING); + glEnable(GL_RESCALE_NORMAL); + glEnable(GL_COLOR_MATERIAL); + + itEnd = Achievements::achievements->end(); + for (AUTO_VAR(it, Achievements::achievements->begin()); it != itEnd; it++) + { + Achievement *ach = *it; //Achievements::achievements->at(i); + + int x = ach->x * ACHIEVEMENT_COORD_SCALE - (int) xScroll; + int y = ach->y * ACHIEVEMENT_COORD_SCALE - (int) yScroll; + + if (x >= -24 && y >= -24 && x <= BIGMAP_WIDTH && y <= BIGMAP_HEIGHT) + { + + if (statsCounter->hasTaken(ach)) + { + float br = 1.0f; + glColor4f(br, br, br, 1); + } + else if (statsCounter->canTake(ach)) + { + float br = (sin(System::currentTimeMillis() % 600 / 600.0 * PI * 2) < 0.6 ? 0.6f : 0.8f); + glColor4f(br, br, br, 1); + } + else + { + float br = 0.3f; + glColor4f(br, br, br, 1); + } + + minecraft->textures->bind(tex); + int xx = xBigMap + x; + int yy = yBigMap + y; + if (ach->isGolden()) + { + this->blit(xx - 2, yy - 2, 26, 202, 26, 26); + } + else + { + this->blit(xx - 2, yy - 2, 0, 202, 26, 26); + } + + if (!statsCounter->canTake(ach)) + { + float br = 0.1f; + glColor4f(br, br, br, 1); + ir->setColor = false; + } + glEnable(GL_LIGHTING); + glEnable(GL_CULL_FACE); + ir->renderGuiItem(minecraft->font, minecraft->textures, ach->icon, xx + 3, yy + 3); + glDisable(GL_LIGHTING); + if (!statsCounter->canTake(ach)) + { + ir->setColor = true; + } + glColor4f(1, 1, 1, 1); + + + if (xm >= xBigMap && ym >= yBigMap && xm < xBigMap + BIGMAP_WIDTH && ym < yBigMap + BIGMAP_HEIGHT && xm >= xx && xm <= xx + 22 && ym >= yy && ym <= yy + 22) { + hoveredAchievement = ach; + } + } + } + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glColor4f(1, 1, 1, 1); + minecraft->textures->bind(tex); + blit(xo, yo, 0, 0, imageWidth, imageHeight); + + + glPopMatrix(); + + blitOffset = 0; + glDepthFunc(GL_LEQUAL); + + glDisable(GL_DEPTH_TEST); + glEnable(GL_TEXTURE_2D); + Screen::render(xm, ym, a); + + if (hoveredAchievement != NULL) + { + Achievement *ach = hoveredAchievement; + wstring name = ach->name; + wstring descr = ach->getDescription(); + + int x = xm + 12; + int y = ym - 4; + + if (statsCounter->canTake(ach)) + { + int width = Math::_max(font->width(name), 120); + int height = font->wordWrapHeight(descr, width); + if (statsCounter->hasTaken(ach)) + { + height += 12; + } + fillGradient(x - 3, y - 3, x + width + 3, y + height + 3 + 12, 0xc0000000, 0xc0000000); + + font->drawWordWrap(descr, x, y + 12, width, 0xffa0a0a0); + if (statsCounter->hasTaken(ach)) + { + font->drawShadow(I18n::get(L"achievement.taken"), x, y + height + 4, 0xff9090ff); + } + } + else + { + int width = Math::_max(font->width(name), 120); + wstring msg = I18n::get(L"achievement.requires", ach->requires->name); + int height = font->wordWrapHeight(msg, width); + fillGradient(x - 3, y - 3, x + width + 3, y + height + 12 + 3, 0xc0000000, 0xc0000000); + font->drawWordWrap(msg, x, y + 12, width, 0xff705050); + } + font->drawShadow(name, x, y, statsCounter->canTake(ach) ? ach->isGolden() ? 0xffffff80 : 0xffffffff : ach->isGolden() ? 0xff808040 : 0xff808080); + + + } + glEnable(GL_DEPTH_TEST); + glEnable(GL_LIGHTING); + Lighting::turnOff(); +#endif +} + +bool AchievementScreen::isPauseScreen() +{ + return true; +} \ No newline at end of file diff --git a/Minecraft.Client/AchievementScreen.h b/Minecraft.Client/AchievementScreen.h new file mode 100644 index 0000000..3c4412e --- /dev/null +++ b/Minecraft.Client/AchievementScreen.h @@ -0,0 +1,57 @@ +#pragma once +#include "Screen.h" +#include "..\Minecraft.World\net.minecraft.stats.h" +class StatsCounter; + +class AchievementScreen : public Screen +{ +private: + static const int BIGMAP_X = 16; + static const int BIGMAP_Y = 17; + static const int BIGMAP_WIDTH = 224; + static const int BIGMAP_HEIGHT = 155; + + // number of pixels per achievement + static const int ACHIEVEMENT_COORD_SCALE = 24; + static const int EDGE_VALUE_X = Achievements::ACHIEVEMENT_WIDTH_POSITION * ACHIEVEMENT_COORD_SCALE; + static const int EDGE_VALUE_Y = Achievements::ACHIEVEMENT_HEIGHT_POSITION * ACHIEVEMENT_COORD_SCALE; + + int xMin; + int yMin; + int xMax; + int yMax; + + static const int MAX_BG_TILE_Y = (EDGE_VALUE_Y * 2 - 1) / 16; + +protected: + int imageWidth; + int imageHeight; + int xLastScroll; + int yLastScroll; + +protected: + double xScrollO, yScrollO; + double xScrollP, yScrollP; + double xScrollTarget, yScrollTarget; + +private: + int scrolling; + StatsCounter *statsCounter; + +public: + using Screen::keyPressed; + + AchievementScreen(StatsCounter *statsCounter); + virtual void init(); +protected: + virtual void buttonClicked(Button *button); + virtual void keyPressed(char eventCharacter, int eventKey); +public: + virtual void render(int mouseX, int mouseY, float a); + virtual void tick(); +protected: + virtual void renderLabels(); + virtual void renderBg(int xm, int ym, float a); +public: + virtual bool isPauseScreen(); +}; diff --git a/Minecraft.Client/AllowAllCuller.cpp b/Minecraft.Client/AllowAllCuller.cpp new file mode 100644 index 0000000..7627af3 --- /dev/null +++ b/Minecraft.Client/AllowAllCuller.cpp @@ -0,0 +1,21 @@ +#include "stdafx.h" +#include "AllowAllCuller.h" + +bool AllowAllCuller::isVisible(AABB *bb) +{ + return true; +} + +bool AllowAllCuller::cubeInFrustum(double x0, double y0, double z0, double x1, double y1, double z1) +{ + return true; +} + +bool AllowAllCuller::cubeFullyInFrustum(double x0, double y0, double z0, double x1, double y1, double z1) +{ + return true; +} + +void AllowAllCuller::prepare(double xOff, double yOff, double zOff) +{ +} \ No newline at end of file diff --git a/Minecraft.Client/AllowAllCuller.h b/Minecraft.Client/AllowAllCuller.h new file mode 100644 index 0000000..5b86604 --- /dev/null +++ b/Minecraft.Client/AllowAllCuller.h @@ -0,0 +1,11 @@ +#pragma once +#include "Culler.h" + +class AllowAllCuller +{ +public: + virtual bool isVisible(AABB *bb); + virtual bool cubeInFrustum(double x0, double y0, double z0, double x1, double y1, double z1); + virtual bool cubeFullyInFrustum(double x0, double y0, double z0, double x1, double y1, double z1); + virtual void prepare(double xOff, double yOff, double zOff); +}; \ No newline at end of file diff --git a/Minecraft.Client/ArchiveFile.cpp b/Minecraft.Client/ArchiveFile.cpp new file mode 100644 index 0000000..642471a --- /dev/null +++ b/Minecraft.Client/ArchiveFile.cpp @@ -0,0 +1,215 @@ +#include "stdafx.h" + +#include "..\Minecraft.World\StringHelpers.h" +#include "..\Minecraft.World\compression.h" + +#include "ArchiveFile.h" + +void ArchiveFile::_readHeader(DataInputStream *dis) +{ + int numberOfFiles = dis->readInt(); + + for (int i = 0; i < numberOfFiles; i++) + { + MetaData *meta = new MetaData(); + meta->filename = dis->readUTF(); + meta->ptr = dis->readInt(); + meta->filesize = dis->readInt(); + + // Filenames preceeded by an asterisk have been compressed. + if (meta->filename[0] == '*') + { + meta->filename = meta->filename.substr(1); + meta->isCompressed = true; + } + else meta->isCompressed = false; + + m_index.insert( pair(meta->filename,meta) ); + } +} + +ArchiveFile::ArchiveFile(File file) +{ + m_cachedData = NULL; + m_sourcefile = file; + app.DebugPrintf("Loading archive file...\n"); +#ifndef _CONTENT_PACKAGE + char buf[256]; + wcstombs(buf, file.getPath().c_str(), 256); + app.DebugPrintf("archive file - %s\n",buf); +#endif + + if(!file.exists()) + { + app.DebugPrintf("Failed to load archive file!\n");//,file.getPath()); + app.FatalLoadError(); + } + + FileInputStream fis(file); + +#if defined _XBOX_ONE || defined __ORBIS__ || defined _WINDOWS64 + byteArray readArray(file.length()); + fis.read(readArray,0,file.length()); + + ByteArrayInputStream bais(readArray); + DataInputStream dis(&bais); + + m_cachedData = readArray.data; +#else + DataInputStream dis(&fis); +#endif + + _readHeader(&dis); + + dis.close(); + fis.close(); +#if defined _XBOX_ONE || defined __ORBIS__ || defined _WINDOWS64 + bais.reset(); +#endif + app.DebugPrintf("Finished loading archive file\n"); +} + +ArchiveFile::~ArchiveFile() +{ + delete m_cachedData; +} + +vector *ArchiveFile::getFileList() +{ + vector *out = new vector(); + + for ( AUTO_VAR(it, m_index.begin()); + it != m_index.end(); + it++ ) + + out->push_back( it->first ); + + return out; +} + +bool ArchiveFile::hasFile(const wstring &filename) +{ + return m_index.find(filename) != m_index.end(); +} + +int ArchiveFile::getFileSize(const wstring &filename) +{ + return hasFile(filename) ? m_index.at(filename)->filesize : -1; +} + +byteArray ArchiveFile::getFile(const wstring &filename) +{ + byteArray out; + AUTO_VAR(it,m_index.find(filename)); + + if(it == m_index.end()) + { + app.DebugPrintf("Couldn't find file in archive\n"); + app.DebugPrintf("Failed to find file '%ls' in archive\n", filename.c_str()); +#ifndef _CONTENT_PACKAGE + __debugbreak(); +#endif + app.FatalLoadError(); + } + else + { + PMetaData data = it->second; + +#if defined _XBOX_ONE || defined __ORBIS__ || defined _WINDOWS64 + out = byteArray(data->filesize ); + + memcpy( out.data, m_cachedData + data->ptr, data->filesize ); +#else + +#ifdef _UNICODE + HANDLE hfile = CreateFile( m_sourcefile.getPath().c_str(), + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); +#else + app.DebugPrintf("Createfile archive\n"); + HANDLE hfile = CreateFile( wstringtofilename(m_sourcefile.getPath()), + GENERIC_READ, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + ); +#endif + + if (hfile != INVALID_HANDLE_VALUE) + { + app.DebugPrintf("hfile ok\n"); + DWORD ok = SetFilePointer( hfile, + data->ptr, + NULL, + FILE_BEGIN + ); + + if (ok != INVALID_SET_FILE_POINTER) + { + PBYTE pbData = new BYTE[ data->filesize ]; + + DWORD bytesRead = -1; + BOOL bSuccess = ReadFile( hfile, + (LPVOID) pbData, + data->filesize, + &bytesRead, + NULL + ); + + if(bSuccess==FALSE) + { + app.FatalLoadError(); + } + assert(bytesRead == data->filesize); + out = byteArray(pbData, data->filesize); + } + else + { + app.FatalLoadError(); + } + + CloseHandle(hfile); + } + else + { + app.DebugPrintf("bad hfile\n"); + app.FatalLoadError(); + } +#endif + + // Compressed filenames are preceeded with an asterisk. + if ( data->isCompressed && out.data != NULL ) + { + /* 4J-JEV: + * If a compressed file is accessed before compression object is + * initialized it will crash here (Compression::getCompression). + */ + ///4 279 553 556 + + ByteArrayInputStream bais(out); + DataInputStream dis(&bais); + unsigned int decompressedSize = dis.readInt(); + dis.close(); + + PBYTE uncompressedBuffer = new BYTE[decompressedSize]; + Compression::getCompression()->Decompress(uncompressedBuffer, &decompressedSize, out.data+4, out.length-4); + + delete [] out.data; + + out.data = uncompressedBuffer; + out.length = decompressedSize; + } + + assert(out.data != NULL); // THERE IS NO FILE WITH THIS NAME! + + } + + return out; +} diff --git a/Minecraft.Client/ArchiveFile.h b/Minecraft.Client/ArchiveFile.h new file mode 100644 index 0000000..722d570 --- /dev/null +++ b/Minecraft.Client/ArchiveFile.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include "..\Minecraft.World\File.h" +#include "..\Minecraft.World\ArrayWithLength.h" + +using namespace std; + +class ArchiveFile +{ +protected: + File m_sourcefile; + BYTE *m_cachedData; + + typedef struct _MetaData + { + wstring filename; + int ptr; + int filesize; + bool isCompressed; + + } MetaData, *PMetaData; + + unordered_map m_index; + +public: + void _readHeader(DataInputStream *dis); + + ArchiveFile(File file); + ~ArchiveFile(); + + vector *getFileList(); + bool hasFile(const wstring &filename); + int getFileSize(const wstring &filename); + byteArray getFile(const wstring &filename); +}; \ No newline at end of file diff --git a/Minecraft.Client/ArrowRenderer.cpp b/Minecraft.Client/ArrowRenderer.cpp new file mode 100644 index 0000000..65c4ee7 --- /dev/null +++ b/Minecraft.Client/ArrowRenderer.cpp @@ -0,0 +1,86 @@ +#include "stdafx.h" +#include "ArrowRenderer.h" +#include "..\Minecraft.World\net.minecraft.world.entity.projectile.h" +#include "..\Minecraft.World\Mth.h" + +void ArrowRenderer::render(shared_ptr _arrow, double x, double y, double z, float rot, float a) +{ + // 4J - original version used generics and thus had an input parameter of type Arrow rather than shared_ptr we have here - + // do some casting around instead + shared_ptr arrow = dynamic_pointer_cast(_arrow); + bindTexture(TN_ITEM_ARROWS); // 4J - was L"/item/arrows.png" + + glPushMatrix(); + + float yRot = arrow->yRot; + float xRot = arrow->xRot; + float yRotO = arrow->yRotO; + float xRotO = arrow->xRotO; + if( ( yRot - yRotO ) > 180.0f ) yRot -= 360.0f; + else if( ( yRot - yRotO ) < -180.0f ) yRot += 360.0f; + if( ( xRot - xRotO ) > 180.0f ) xRot -= 360.0f; + else if( ( xRot - xRotO ) < -180.0f ) xRot += 360.0f; + + glTranslatef((float)x, (float)y, (float)z); + glRotatef(yRotO + (yRot - yRotO) * a - 90, 0, 1, 0); + glRotatef(xRotO + (xRot - xRotO) * a, 0, 0, 1); + + Tesselator *t = Tesselator::getInstance(); + int type = 0; + + float u0 = 0 / 32.0f; + float u1 = 16 / 32.0f; + float v0 = (0 + type * 10) / 32.0f; + float v1 = (5 + type * 10) / 32.0f; + + float u02 = 0 / 32.0f; + float u12 = 5 / 32.0f; + float v02 = (5 + type * 10) / 32.0f; + float v12 = (10 + type * 10) / 32.0f; + float ss = 0.9f / 16.0f; + glEnable(GL_RESCALE_NORMAL); + float shake = arrow->shakeTime-a; + if (shake>0) + { + float pow = -Mth::sin(shake*3)*shake; + glRotatef(pow, 0, 0, 1); + } + glRotatef(45, 1, 0, 0); + glScalef(ss, ss, ss); + + glTranslatef(-4, 0, 0); + +// glNormal3f(ss, 0, 0); // 4J - changed to use tesselator + t->begin(); + t->normal(1,0,0); + t->vertexUV((float)(-7), (float)( -2), (float)( -2), (float)( u02), (float)( v02)); + t->vertexUV((float)(-7), (float)( -2), (float)( +2), (float)( u12), (float)( v02)); + t->vertexUV((float)(-7), (float)( +2), (float)( +2), (float)( u12), (float)( v12)); + t->vertexUV((float)(-7), (float)( +2), (float)( -2), (float)( u02), (float)( v12)); + t->end(); + +// glNormal3f(-ss, 0, 0); // 4J - changed to use tesselator + t->begin(); + t->normal(-1,0,0); + t->vertexUV((float)(-7), (float)( +2), (float)( -2), (float)( u02), (float)( v02)); + t->vertexUV((float)(-7), (float)( +2), (float)( +2), (float)( u12), (float)( v02)); + t->vertexUV((float)(-7), (float)( -2), (float)( +2), (float)( u12), (float)( v12)); + t->vertexUV((float)(-7), (float)( -2), (float)( -2), (float)( u02), (float)( v12)); + t->end(); + + for (int i = 0; i < 4; i++) + { + + glRotatef(90, 1, 0, 0); +// glNormal3f(0, 0, ss); // 4J - changed to use tesselator + t->begin(); + t->normal(0,0,1); + t->vertexUV((float)(-8), (float)( -2), (float)( 0), (float)( u0), (float)( v0)); + t->vertexUV((float)(+8), (float)( -2), (float)( 0), (float)( u1), (float)( v0)); + t->vertexUV((float)(+8), (float)( +2), (float)( 0), (float)( u1), (float)( v1)); + t->vertexUV((float)(-8), (float)( +2), (float)( 0), (float)( u0), (float)( v1)); + t->end(); + } + glDisable(GL_RESCALE_NORMAL); + glPopMatrix(); +} \ No newline at end of file diff --git a/Minecraft.Client/ArrowRenderer.h b/Minecraft.Client/ArrowRenderer.h new file mode 100644 index 0000000..2731f7c --- /dev/null +++ b/Minecraft.Client/ArrowRenderer.h @@ -0,0 +1,8 @@ +#pragma once +#include "EntityRenderer.h" + +class ArrowRenderer : public EntityRenderer +{ +public: + virtual void render(shared_ptr _arrow, double x, double y, double z, float rot, float a); +}; diff --git a/Minecraft.Client/BlazeModel.cpp b/Minecraft.Client/BlazeModel.cpp new file mode 100644 index 0000000..5af894a --- /dev/null +++ b/Minecraft.Client/BlazeModel.cpp @@ -0,0 +1,76 @@ +#include "stdafx.h" +#include "..\Minecraft.World\Mth.h" +#include "BlazeModel.h" +#include "ModelPart.h" + +BlazeModel::BlazeModel() : Model() +{ + upperBodyParts = ModelPartArray(12); + + for (unsigned int i = 0; i < upperBodyParts.length; i++) + { + upperBodyParts[i] = new ModelPart(this, 0, 16); + upperBodyParts[i]->addBox(0, 0, 0, 2, 8, 2); + } + + head = new ModelPart(this, 0, 0); + head->addBox(-4, -4, -4, 8, 8, 8); + + // 4J added - compile now to avoid random performance hit first time cubes are rendered + // 4J Stu - Not just performance, but alpha+depth tests don't work right unless we compile here + for (unsigned int i = 0; i < upperBodyParts.length; i++) + { + upperBodyParts[i]->compile(1.0f/16.0f); + } + head->compile(1.0f/16.0f); +} + +int BlazeModel::modelVersion() +{ + return 8; +} + +void BlazeModel::render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled) +{ + setupAnim(time, r, bob, yRot, xRot, scale); + + head->render(scale,usecompiled); + for (unsigned int i = 0; i < upperBodyParts.length; i++) + { + upperBodyParts[i]->render(scale, usecompiled); + } +} + +void BlazeModel::setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim) +{ + + float angle = bob * PI * -.1f; + for (int i = 0; i < 4; i++) + { + upperBodyParts[i]->y = -2 + Mth::cos((i * 2 + bob) * .25f); + upperBodyParts[i]->x = Mth::cos(angle) * 9.0f; + upperBodyParts[i]->z = Mth::sin(angle) * 9.0f; + angle += PI * 0.5f; + } + angle = .25f * PI + bob * PI * .03f; + for (int i = 4; i < 8; i++) + { + upperBodyParts[i]->y = 2 + Mth::cos((i * 2 + bob) * .25f); + upperBodyParts[i]->x = Mth::cos(angle) * 7.0f; + upperBodyParts[i]->z = Mth::sin(angle) * 7.0f; + angle += PI * 0.5f; + } + + angle = .15f * PI + bob * PI * -.05f; + for (int i = 8; i < 12; i++) + { + upperBodyParts[i]->y = 11 + Mth::cos((i * 1.5f + bob) * .5f); + upperBodyParts[i]->x = Mth::cos(angle) * 5.0f; + upperBodyParts[i]->z = Mth::sin(angle) * 5.0f; + angle += PI * 0.5f; + } + + head->yRot = yRot / (float) (180 / PI); + head->xRot = xRot / (float) (180 / PI); +} + diff --git a/Minecraft.Client/BlazeModel.h b/Minecraft.Client/BlazeModel.h new file mode 100644 index 0000000..27ee206 --- /dev/null +++ b/Minecraft.Client/BlazeModel.h @@ -0,0 +1,16 @@ +#pragma once +#include "Model.h" + +class BlazeModel : public Model +{ + +private: + ModelPartArray upperBodyParts; + ModelPart *head; + +public: + BlazeModel(); + int modelVersion(); + virtual void render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled); + virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim=0); +}; diff --git a/Minecraft.Client/BlazeRenderer.cpp b/Minecraft.Client/BlazeRenderer.cpp new file mode 100644 index 0000000..7d5210d --- /dev/null +++ b/Minecraft.Client/BlazeRenderer.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" +#include "BlazeModel.h" +#include "..\Minecraft.World\net.minecraft.world.entity.monster.h" +#include "BlazeRenderer.h" + +BlazeRenderer::BlazeRenderer() : MobRenderer(new BlazeModel(), 0.5f) +{ + this->modelVersion = ((BlazeModel *) model)->modelVersion(); +} + +void BlazeRenderer::render(shared_ptr _mob, double x, double y, double z, float rot, float a) +{ + // 4J - original version used generics and thus had an input parameter of type Blaze rather than shared_ptr we have here - + // do some casting around instead + shared_ptr mob = dynamic_pointer_cast(_mob); + + int modelVersion = ((BlazeModel *) model)->modelVersion(); + if (modelVersion != this->modelVersion) + { + this->modelVersion = modelVersion; + model = new BlazeModel(); + } + MobRenderer::render(mob, x, y, z, rot, a); +} \ No newline at end of file diff --git a/Minecraft.Client/BlazeRenderer.h b/Minecraft.Client/BlazeRenderer.h new file mode 100644 index 0000000..fc575e9 --- /dev/null +++ b/Minecraft.Client/BlazeRenderer.h @@ -0,0 +1,14 @@ +#pragma once + +#include "MobRenderer.h" + +class BlazeRenderer : public MobRenderer +{ +private: + int modelVersion; + +public: + BlazeRenderer(); + + virtual void render(shared_ptr mob, double x, double y, double z, float rot, float a); +}; \ No newline at end of file diff --git a/Minecraft.Client/BoatModel.cpp b/Minecraft.Client/BoatModel.cpp new file mode 100644 index 0000000..d0d465e --- /dev/null +++ b/Minecraft.Client/BoatModel.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "BoatModel.h" + +BoatModel::BoatModel() : Model() +{ + cubes[0] = new ModelPart(this, 0, 8); + cubes[1] = new ModelPart(this, 0, 0); + cubes[2] = new ModelPart(this, 0, 0); + cubes[3] = new ModelPart(this, 0, 0); + cubes[4] = new ModelPart(this, 0, 0); + + int w = 24; + int d = 6; + int h = 20; + int yOff = 4; + + cubes[0]->addBox((float)(-w / 2), (float)(-h / 2 + 2), -3, w, h - 4, 4, 0); + cubes[0]->setPos(0, (float)(0 + yOff), 0); + + cubes[1]->addBox((float)(-w / 2 + 2), (float)(-d - 1), -1, w - 4, d, 2, 0); + cubes[1]->setPos((float)(-w / 2 + 1), (float)(0 + yOff), 0); + + cubes[2]->addBox((float)(-w / 2 + 2), (float)(-d - 1), -1, w - 4, d, 2, 0); + cubes[2]->setPos((float)(+w / 2 - 1), (float)(0 + yOff), 0); + + cubes[3]->addBox((float)(-w / 2 + 2), (float)(-d - 1), -1, w - 4, d, 2, 0); + cubes[3]->setPos(0, (float)(0 + yOff), (float)(-h / 2 + 1)); + + cubes[4]->addBox((float)(-w / 2 + 2), (float)(-d - 1), -1, w - 4, d, 2, 0); + cubes[4]->setPos(0, (float)(0 + yOff), (float)(+h / 2 - 1)); + + cubes[0]->xRot = PI / 2; + cubes[1]->yRot = PI / 2 * 3; + cubes[2]->yRot = PI / 2 * 1; + cubes[3]->yRot = PI / 2 * 2; + + // 4J added - compile now to avoid random performance hit first time cubes are rendered + cubes[0]->compile(1.0f/16.0f); + cubes[1]->compile(1.0f/16.0f); + cubes[2]->compile(1.0f/16.0f); + cubes[3]->compile(1.0f/16.0f); + cubes[4]->compile(1.0f/16.0f); +} + +void BoatModel::render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled) +{ + for (int i = 0; i < 5; i++) + { + cubes[i]->render(scale, usecompiled); + } +} \ No newline at end of file diff --git a/Minecraft.Client/BoatModel.h b/Minecraft.Client/BoatModel.h new file mode 100644 index 0000000..4298b64 --- /dev/null +++ b/Minecraft.Client/BoatModel.h @@ -0,0 +1,11 @@ +#pragma once +#include "Model.h" +#include "ModelPart.h" + +class BoatModel : public Model +{ +public: + ModelPart *cubes[5]; + BoatModel(); + virtual void render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled); +}; \ No newline at end of file diff --git a/Minecraft.Client/BoatRenderer.cpp b/Minecraft.Client/BoatRenderer.cpp new file mode 100644 index 0000000..f1367ae --- /dev/null +++ b/Minecraft.Client/BoatRenderer.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include "BoatRenderer.h" +#include "BoatModel.h" +#include "..\Minecraft.World\net.minecraft.world.entity.item.h" +#include "..\Minecraft.World\Mth.h" + +BoatRenderer::BoatRenderer() : EntityRenderer() +{ + this->shadowRadius = 0.5f; + model = new BoatModel(); +} + +void BoatRenderer::render(shared_ptr _boat, double x, double y, double z, float rot, float a) +{ + // 4J - original version used generics and thus had an input parameter of type Boat rather than shared_ptr we have here - + // do some casting around instead + shared_ptr boat = dynamic_pointer_cast(_boat); + + glPushMatrix(); + + glTranslatef((float) x, (float) y, (float) z); + + glRotatef(180-rot, 0, 1, 0); + float hurt = boat->getHurtTime() - a; + float dmg = boat->getDamage() - a; + if (dmg<0) dmg = 0; + if (hurt>0) + { + glRotatef(Mth::sin(hurt)*hurt*dmg/10*boat->getHurtDir(), 1, 0, 0); + } + + bindTexture(TN_TERRAIN); // 4J was L"/terrain.png" + float ss = 12/16.0f; + glScalef(ss, ss, ss); + glScalef(1/ss, 1/ss, 1/ss); + + bindTexture(TN_ITEM_BOAT); // 4J was L"/item/boat.png" + glScalef(-1, -1, 1); + model->render(boat, 0, 0, -0.1f, 0, 0, 1 / 16.0f, true); + glPopMatrix(); +} \ No newline at end of file diff --git a/Minecraft.Client/BoatRenderer.h b/Minecraft.Client/BoatRenderer.h new file mode 100644 index 0000000..1cc9c1d --- /dev/null +++ b/Minecraft.Client/BoatRenderer.h @@ -0,0 +1,13 @@ +#pragma once +#include "EntityRenderer.h" + +class BoatRenderer : public EntityRenderer +{ +protected: + Model *model; + +public: + BoatRenderer(); + + virtual void render(shared_ptr boat, double x, double y, double z, float rot, float a); +}; \ No newline at end of file diff --git a/Minecraft.Client/BookModel.cpp b/Minecraft.Client/BookModel.cpp new file mode 100644 index 0000000..bc4769b --- /dev/null +++ b/Minecraft.Client/BookModel.cpp @@ -0,0 +1,68 @@ +#include "stdafx.h" +#include "..\Minecraft.World\Mth.h" +#include "BookModel.h" +#include "ModelPart.h" + +BookModel::BookModel() +{ + leftLid = (new ModelPart(this))->texOffs(0, 0)->addBox(-6, -5, 0, 6, 10, 0); + rightLid = (new ModelPart(this))->texOffs(16, 0)->addBox(0, -5, 0, 6, 10, 0); + + seam = (new ModelPart(this))->texOffs(12, 0)->addBox(-1, -5, 0, 2, 10, 0); + + // 4J - added faceMasks here to remove sides of these page boxes which end up being nearly coplanar to the cover of the book and flickering when rendering at a distance + leftPages = (new ModelPart(this))->texOffs(0, 10)->addBoxWithMask(0, -4, -1 + 0.01f, 5, 8, 1, 47); // 4J - faceMask is binary 101111 + rightPages = (new ModelPart(this))->texOffs(12, 10)->addBoxWithMask(0, -4, -0.01f, 5, 8, 1, 31); // 4J - faceMask is binary 011111 + + flipPage1 = (new ModelPart(this))->texOffs(24, 10)->addBox(0, -4, 0, 5, 8, 0); + flipPage2 = (new ModelPart(this))->texOffs(24, 10)->addBox(0, -4, 0, 5, 8, 0); + + leftLid->setPos(0, 0, -1); + rightLid->setPos(0, 0, 1); + + seam->yRot = PI / 2; + + // 4J added - compile now to avoid random performance hit first time cubes are rendered + leftLid->compile(1.0f/16.0f); + rightLid->compile(1.0f/16.0f); + seam->compile(1.0f/16.0f); + leftPages->compile(1.0f/16.0f); + rightPages->compile(1.0f/16.0f); + flipPage1->compile(1.0f/16.0f); + flipPage2->compile(1.0f/16.0f); + +} + +void BookModel::render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled) +{ + setupAnim(time, r, bob, yRot, xRot, scale); + + leftLid->render(scale,usecompiled); + rightLid->render(scale,usecompiled); + seam->render(scale,usecompiled); + + leftPages->render(scale,usecompiled); + rightPages->render(scale,usecompiled); + + flipPage1->render(scale,usecompiled); + flipPage2->render(scale,usecompiled); +} + +void BookModel::setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim) +{ + float openness = (Mth::sin(time * 0.02f) * 0.10f + 1.25f) * yRot; + + leftLid->yRot = PI + openness; + rightLid->yRot = -openness; + leftPages->yRot = +openness; + rightPages->yRot = -openness; + + flipPage1->yRot = +openness - openness * 2 * r; + flipPage2->yRot = +openness - openness * 2 * bob; + + leftPages->x = Mth::sin(openness); + rightPages->x = Mth::sin(openness); + flipPage1->x = Mth::sin(openness); + flipPage2->x = Mth::sin(openness); +} + diff --git a/Minecraft.Client/BookModel.h b/Minecraft.Client/BookModel.h new file mode 100644 index 0000000..8b367a3 --- /dev/null +++ b/Minecraft.Client/BookModel.h @@ -0,0 +1,16 @@ + +#pragma once +#include "Model.h" + +class BookModel : public Model +{ +public: + ModelPart *leftLid, *rightLid; + ModelPart *leftPages, *rightPages; + ModelPart *flipPage1, *flipPage2; + ModelPart *seam; + + BookModel(); + virtual void render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled); + virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim=0); +}; diff --git a/Minecraft.Client/BreakingItemParticle.cpp b/Minecraft.Client/BreakingItemParticle.cpp new file mode 100644 index 0000000..51b721f --- /dev/null +++ b/Minecraft.Client/BreakingItemParticle.cpp @@ -0,0 +1,64 @@ +#include "stdafx.h" +#include "BreakingItemParticle.h" +#include "Tesselator.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\Minecraft.World\net.minecraft.world.item.h" +#include "..\Minecraft.World\net.minecraft.world.h" + +void BreakingItemParticle::_init(Item *item, Textures *textures, int data) +{ + this->setTex(textures, item->getIcon(data)); + rCol = gCol = bCol = 1.0f; + gravity = Tile::snow->gravity; + size /= 2; +} + +BreakingItemParticle::BreakingItemParticle(Level *level, double x, double y, double z, Item *item, Textures *textures, int data) : Particle(level, x, y, z, 0, 0, 0) +{ + _init(item, textures, data); +} + +BreakingItemParticle::BreakingItemParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Item *item, Textures *textures, int data) : Particle(level, x, y, z, 0, 0, 0) +{ + _init(item, textures, data); + xd *= 0.1f; + yd *= 0.1f; + zd *= 0.1f; + xd += xa; + yd += ya; + zd += za; +} + +int BreakingItemParticle::getParticleTexture() +{ + return ParticleEngine::ITEM_TEXTURE; +} + +void BreakingItemParticle::render(Tesselator *t, float a, float xa, float ya, float za, float xa2, float za2) +{ + float u0 = (texX + uo / 4.0f) / 16.0f; + float u1 = u0 + 0.999f / 16.0f / 4; + float v0 = (texY + vo / 4.0f) / 16.0f; + float v1 = v0 + 0.999f / 16.0f / 4; + float r = 0.1f * size; + + if (tex != NULL) + { + u0 = tex->getU((uo / 4.0f) * SharedConstants::WORLD_RESOLUTION); + u1 = tex->getU(((uo + 1) / 4.0f) * SharedConstants::WORLD_RESOLUTION); + v0 = tex->getV((vo / 4.0f) * SharedConstants::WORLD_RESOLUTION); + v1 = tex->getV(((vo + 1) / 4.0f) * SharedConstants::WORLD_RESOLUTION); + } + + float x = (float) (xo + (this->x - xo) * a - xOff); + float y = (float) (yo + (this->y - yo) * a - yOff); + float z = (float) (zo + (this->z - zo) * a - zOff); + float br = SharedConstants::TEXTURE_LIGHTING ? 1 : getBrightness(a); // 4J - change brought forward from 1.8.2 + t->color(br * rCol, br * gCol, br * bCol); + + t->vertexUV((float)(x - xa * r - xa2 * r), (float)( y - ya * r), (float)( z - za * r - za2 * r), (float)( u0), (float)( v1)); + t->vertexUV((float)(x - xa * r + xa2 * r), (float)( y + ya * r), (float)( z - za * r + za2 * r), (float)( u0), (float)( v0)); + t->vertexUV((float)(x + xa * r + xa2 * r), (float)( y + ya * r), (float)( z + za * r + za2 * r), (float)( u1), (float)( v0)); + t->vertexUV((float)(x + xa * r - xa2 * r), (float)( y - ya * r), (float)( z + za * r - za2 * r), (float)( u1), (float)( v1)); + +} \ No newline at end of file diff --git a/Minecraft.Client/BreakingItemParticle.h b/Minecraft.Client/BreakingItemParticle.h new file mode 100644 index 0000000..390426d --- /dev/null +++ b/Minecraft.Client/BreakingItemParticle.h @@ -0,0 +1,15 @@ +#pragma once +#include "Particle.h" + +class BreakingItemParticle : public Particle +{ + // virtual eINSTANCEOF GetType(); // 4J-IB/JEV TODO needs implementation + +public: + virtual eINSTANCEOF GetType() { return eType_BREAKINGITEMPARTICLE; } + void _init(Item *item, Textures *textures, int data); + BreakingItemParticle(Level *level, double x, double y, double z, Item *item, Textures *textures, int data = 0); + BreakingItemParticle(Level *level, double x, double y, double z, double xa, double ya, double za, Item *item, Textures *textures, int data = 0); + virtual int getParticleTexture(); + virtual void render(Tesselator *t, float a, float xa, float ya, float za, float xa2, float za2); +}; diff --git a/Minecraft.Client/BubbleParticle.cpp b/Minecraft.Client/BubbleParticle.cpp new file mode 100644 index 0000000..2d1380e --- /dev/null +++ b/Minecraft.Client/BubbleParticle.cpp @@ -0,0 +1,41 @@ +#include "stdafx.h" +#include "BubbleParticle.h" +#include "..\Minecraft.World\Random.h" +#include "..\Minecraft.World\Mth.h" +#include "..\Minecraft.World\JavaMath.h" +#include "..\Minecraft.World\net.minecraft.world.level.h" +#include "..\Minecraft.World\net.minecraft.world.level.material.h" + +BubbleParticle::BubbleParticle(Level *level, double x, double y, double z, double xa, double ya, double za) : Particle(level, x, y, z, xa, ya, za) + { + rCol = 1.0f; + gCol = 1.0f; + bCol = 1.0f; + setMiscTex(32); + this->setSize(0.02f, 0.02f); + + size = size*(random->nextFloat()*0.6f+0.2f); + + xd = xa*0.2f+(float)(Math::random()*2-1)*0.02f; + yd = ya*0.2f+(float)(Math::random()*2-1)*0.02f; + zd = za*0.2f+(float)(Math::random()*2-1)*0.02f; + + lifetime = (int) (8 / (Math::random() * 0.8 + 0.2)); +} + +void BubbleParticle::tick() +{ + xo = x; + yo = y; + zo = z; + + yd += 0.002; + move(xd, yd, zd); + xd *= 0.85f; + yd *= 0.85f; + zd *= 0.85f; + + if (level->getMaterial(Mth::floor(x), Mth::floor(y), Mth::floor(z)) != Material::water) remove(); + + if (lifetime-- <= 0) remove(); +} \ No newline at end of file diff --git a/Minecraft.Client/BubbleParticle.h b/Minecraft.Client/BubbleParticle.h new file mode 100644 index 0000000..0e786d9 --- /dev/null +++ b/Minecraft.Client/BubbleParticle.h @@ -0,0 +1,10 @@ +#pragma once +#include "Particle.h" + +class BubbleParticle : public Particle +{ +public: + virtual eINSTANCEOF GetType() { return eType_BUBBLEPARTICLE; } + BubbleParticle(Level *level, double x, double y, double z, double xa, double ya, double za); + virtual void tick(); +}; \ No newline at end of file diff --git a/Minecraft.Client/BufferedImage.cpp b/Minecraft.Client/BufferedImage.cpp new file mode 100644 index 0000000..658e934 --- /dev/null +++ b/Minecraft.Client/BufferedImage.cpp @@ -0,0 +1,400 @@ +#include "stdafx.h" +#include "..\Minecraft.World\StringHelpers.h" +#include "Textures.h" +#include "..\Minecraft.World\ArrayWithLength.h" +#include "BufferedImage.h" + +#ifdef _XBOX +typedef struct +{ + unsigned int filesz; + unsigned short creator1; + unsigned short creator2; + unsigned int bmp_offset; + unsigned int header_sz; + unsigned int width; + unsigned int height; + unsigned short nplanes; + unsigned short bitspp; + unsigned int compress_type; + unsigned int bmp_bytesz; + int hres; + int vres; + unsigned int ncolors; + unsigned int nimpcolors; +} BITMAPINFOHEADER; +#endif + +BufferedImage::BufferedImage(int width,int height,int type) +{ + data[0] = new int[width*height]; + + for( int i = 1 ; i < 10; i++ ) + { + data[i] = NULL; + } + this->width = width; + this->height = height; +} + +void BufferedImage::ByteFlip4(unsigned int &data) +{ + data = ( data >> 24 ) | + ( ( data >> 8 ) & 0x0000ff00 ) | + ( ( data << 8 ) & 0x00ff0000 ) | + ( data << 24 ); +} +// Loads a bitmap into a buffered image - only currently supports the 2 types of 32-bit image that we've made so far +// and determines which of these is which by the compression method. Compression method 3 is a 32-bit image with only +// 24-bits used (ie no alpha channel) whereas method 0 is a full 32-bit image with a valid alpha channel. +BufferedImage::BufferedImage(const wstring& File, bool filenameHasExtension /*=false*/, bool bTitleUpdateTexture /*=false*/, const wstring &drive /*=L""*/) +{ + HRESULT hr; + wstring wDrive; + wstring filePath; + filePath = File; + + wDrive = drive; + if(wDrive.empty()) + { +#ifdef _XBOX + if(bTitleUpdateTexture) + { + // Make the content package point to to the UPDATE: drive is needed +#ifdef _TU_BUILD + wDrive=L"UPDATE:\\"; +#else + + wDrive=L"GAME:\\res\\TitleUpdate\\"; +#endif + } + else + { + wDrive=L"GAME:\\"; + } +#else + +#ifdef __PS3__ + + char *pchUsrDir; + if(app.GetBootedFromDiscPatch()) + { + const char *pchTextureName=wstringtofilename(File); + pchUsrDir = app.GetBDUsrDirPath(pchTextureName); + } + else + { + pchUsrDir=getUsrDirPath(); + } + + wstring wstr (pchUsrDir, pchUsrDir+strlen(pchUsrDir)); + + if(bTitleUpdateTexture) + { + // Make the content package point to to the UPDATE: drive is needed + wDrive= wstr + L"\\Common\\res\\TitleUpdate\\"; + } + else + { + wDrive= wstr + L"/Common/"; + } +#elif __PSVITA__ + + /*char *pchUsrDir=getUsrDirPath(); + + wstring wstr (pchUsrDir, pchUsrDir+strlen(pchUsrDir)); + + if(bTitleUpdateTexture) + { + // Make the content package point to to the UPDATE: drive is needed + wDrive= wstr + L"\\Common\\res\\TitleUpdate\\"; + } + else + { + wDrive= wstr + L"/Common/"; + }*/ + + if(bTitleUpdateTexture) + { + // Make the content package point to to the UPDATE: drive is needed + wDrive= L"Common\\res\\TitleUpdate\\"; + } + else + { + wDrive= L"Common/"; + } +#else + if(bTitleUpdateTexture) + { + // Make the content package point to to the UPDATE: drive is needed + wDrive= L"Common\\res\\TitleUpdate\\"; + } + else + { + wDrive= L"Common/"; + } +#endif + +#endif + } + + for( int l = 0 ; l < 10; l++ ) + { + data[l] = NULL; + } + + for( int l = 0; l < 10; l++ ) + { + wstring name; + wstring mipMapPath = L""; + if( l != 0 ) + { + mipMapPath = L"MipMapLevel" + _toString(l+1); + } + if( filenameHasExtension ) + { + name = wDrive + L"res" + filePath.substr(0,filePath.length()); + } + else + { + name = wDrive + L"res" + filePath.substr(0,filePath.length()-4) + mipMapPath + L".png"; + } + + const char *pchTextureName=wstringtofilename(name); + +#ifdef _DEBUG + app.DebugPrintf("\n--- Loading TEXTURE - %s\n\n",pchTextureName); +#endif + + D3DXIMAGE_INFO ImageInfo; + ZeroMemory(&ImageInfo,sizeof(D3DXIMAGE_INFO)); + hr=RenderManager.LoadTextureData(pchTextureName,&ImageInfo,&data[l]); + + + if(hr!=ERROR_SUCCESS) + { + // 4J - If we haven't loaded the non-mipmap version then exit the game + if( l == 0 ) + { + app.FatalLoadError(); + } + return; + } + + if( l == 0 ) + { + width=ImageInfo.Width; + height=ImageInfo.Height; + } + } +} + +BufferedImage::BufferedImage(DLCPack *dlcPack, const wstring& File, bool filenameHasExtension /*= false*/ ) +{ + HRESULT hr; + wstring filePath = File; + BYTE *pbData = NULL; + DWORD dwBytes = 0; + + for( int l = 0 ; l < 10; l++ ) + { + data[l] = NULL; + } + + for( int l = 0; l < 10; l++ ) + { + wstring name; + wstring mipMapPath = L""; + if( l != 0 ) + { + mipMapPath = L"MipMapLevel" + _toString(l+1); + } + if( filenameHasExtension ) + { + name = L"res" + filePath.substr(0,filePath.length()); + } + else + { + name = L"res" + filePath.substr(0,filePath.length()-4) + mipMapPath + L".png"; + } + + if(!dlcPack->doesPackContainFile(DLCManager::e_DLCType_All, name)) + { + // 4J - If we haven't loaded the non-mipmap version then exit the game + if( l == 0 ) + { + app.FatalLoadError(); + } + return; + } + + DLCFile *dlcFile = dlcPack->getFile(DLCManager::e_DLCType_All, name); + pbData = dlcFile->getData(dwBytes); + if(pbData == NULL || dwBytes == 0) + { + // 4J - If we haven't loaded the non-mipmap version then exit the game + if( l == 0 ) + { + app.FatalLoadError(); + } + return; + } + + D3DXIMAGE_INFO ImageInfo; + ZeroMemory(&ImageInfo,sizeof(D3DXIMAGE_INFO)); + hr=RenderManager.LoadTextureData(pbData,dwBytes,&ImageInfo,&data[l]); + + + if(hr!=ERROR_SUCCESS) + { + // 4J - If we haven't loaded the non-mipmap version then exit the game + if( l == 0 ) + { + app.FatalLoadError(); + } + return; + } + + if( l == 0 ) + { + width=ImageInfo.Width; + height=ImageInfo.Height; + } + } +} + + +BufferedImage::BufferedImage(BYTE *pbData, DWORD dwBytes) +{ + int iCurrentByte=0; + for( int l = 0 ; l < 10; l++ ) + { + data[l] = NULL; + } + + D3DXIMAGE_INFO ImageInfo; + ZeroMemory(&ImageInfo,sizeof(D3DXIMAGE_INFO)); + HRESULT hr=RenderManager.LoadTextureData(pbData,dwBytes,&ImageInfo,&data[0]); + + if(hr==ERROR_SUCCESS) + { + width=ImageInfo.Width; + height=ImageInfo.Height; + } + else + { + app.FatalLoadError(); + } +} + +BufferedImage::~BufferedImage() +{ + for(int i = 0; i < 10; i++ ) + { + delete[] data[i]; + } +} + +int BufferedImage::getWidth() +{ + return width; +} + +int BufferedImage::getHeight() +{ + return height; +} + +void BufferedImage::getRGB(int startX, int startY, int w, int h, intArray out,int offset,int scansize, int level) +{ + int ww = width >> level; + for( int y = 0; y < h; y++ ) + { + for( int x = 0; x < w; x++ ) + { + out[ y * scansize + offset + x] = data[level][ startX + x + ww * ( startY + y ) ]; + } + } +} + +int *BufferedImage::getData() +{ + return data[0]; +} + +int *BufferedImage::getData(int level) +{ + return data[level]; +} + +Graphics *BufferedImage::getGraphics() +{ + return NULL; +} + +//Returns the transparency. Returns either OPAQUE, BITMASK, or TRANSLUCENT. +//Specified by: +//getTransparency in interface Transparency +//Returns: +//the transparency of this BufferedImage. +int BufferedImage::getTransparency() +{ + // TODO - 4J Implement? + return 0; +} + +//Returns a subimage defined by a specified rectangular region. The returned BufferedImage shares the same data array as the original image. +//Parameters: +//x, y - the coordinates of the upper-left corner of the specified rectangular region +//w - the width of the specified rectangular region +//h - the height of the specified rectangular region +//Returns: +//a BufferedImage that is the subimage of this BufferedImage. +BufferedImage *BufferedImage::getSubimage(int x ,int y, int w, int h) +{ + // TODO - 4J Implement + + BufferedImage *img = new BufferedImage(w,h,0); + intArray arrayWrapper(img->data[0], w*h); + this->getRGB(x, y, w, h, arrayWrapper,0,w); + + int level = 1; + while(getData(level) != NULL) + { + int ww = w >> level; + int hh = h >> level; + int xx = x >> level; + int yy = y >> level; + img->data[level] = new int[ww*hh]; + intArray arrayWrapper(img->data[level], ww*hh); + this->getRGB(xx, yy, ww, hh, arrayWrapper,0,ww,level); + + ++level; + } + + return img; +} + + +void BufferedImage::preMultiplyAlpha() +{ + int *curData = data[0]; + + int cur = 0; + int alpha = 0; + int r = 0; + int g = 0; + int b = 0; + + int total = width * height; + for(unsigned int i = 0; i < total; ++i) + { + cur = curData[i]; + alpha = (cur >> 24) & 0xff; + r = ((cur >> 16) & 0xff) * (float)alpha/255; + g = ((cur >> 8) & 0xff) * (float)alpha/255; + b = (cur & 0xff) * (float)alpha/255; + + curData[i] = (r << 16) | (g << 8) | (b ) | (alpha << 24); + } +} diff --git a/Minecraft.Client/BufferedImage.h b/Minecraft.Client/BufferedImage.h new file mode 100644 index 0000000..a0227fe --- /dev/null +++ b/Minecraft.Client/BufferedImage.h @@ -0,0 +1,33 @@ +#pragma once +using namespace std; + +class Graphics; +class DLCPack; + +class BufferedImage +{ +private: + int *data[10]; // Arrays for mipmaps - NULL if not used + int width; + int height; + void ByteFlip4(unsigned int &data); // 4J added +public: + static const int TYPE_INT_ARGB = 0; + static const int TYPE_INT_RGB = 1; + BufferedImage(int width,int height,int type); + BufferedImage(const wstring& File, bool filenameHasExtension = false, bool bTitleUpdateTexture=false, const wstring &drive =L""); // 4J added + BufferedImage(DLCPack *dlcPack, const wstring& File, bool filenameHasExtension = false ); // 4J Added + BufferedImage(BYTE *pbData, DWORD dwBytes); // 4J added + ~BufferedImage(); + + int getWidth(); + int getHeight(); + void getRGB(int startX, int startY, int w, int h, intArray out,int offset,int scansize, int level = 0); // 4J Added level param + int *getData(); // 4J added + int *getData(int level); // 4J added + Graphics *getGraphics(); + int getTransparency(); + BufferedImage *getSubimage(int x, int y, int w, int h); + + void preMultiplyAlpha(); +}; \ No newline at end of file diff --git a/Minecraft.Client/Button.cpp b/Minecraft.Client/Button.cpp new file mode 100644 index 0000000..7de105c --- /dev/null +++ b/Minecraft.Client/Button.cpp @@ -0,0 +1,85 @@ +#include "stdafx.h" +#include "Button.h" +#include "Textures.h" + +Button::Button(int id, int x, int y, const wstring& msg) +{ + init(id, x, y, 200, 20, msg); +} + +Button::Button(int id, int x, int y, int w, int h, const wstring& msg) +{ + init(id, x, y, w, h, msg); +} + +// 4J - added +void Button::init(int id, int x, int y, int w, int h, const wstring& msg) +{ + active = true; + visible = true; + + // this bit of code from original ctor + this->id = id; + this->x = x; + this->y = y; + this->w = w; + this->h = h; + this->msg = msg; +} + +int Button::getYImage(bool hovered) +{ + int res = 1; + if (!active) res = 0; + else if (hovered) res = 2; + return res; +} + +void Button::render(Minecraft *minecraft, int xm, int ym) +{ + if (!visible) return; + + Font *font = minecraft->font; + + glBindTexture(GL_TEXTURE_2D, minecraft->textures->loadTexture(TN_GUI_GUI)); // 4J was L"/gui/gui.png" + glColor4f(1, 1, 1, 1); + + + bool hovered = xm >= x && ym >= y && xm < x + w && ym < y + h; + int yImage = getYImage(hovered); + + blit(x, y, 0, 46 + yImage * 20, w / 2, h); + blit(x + w / 2, y, 200 - w / 2, 46 + yImage * 20, w / 2, h); + + renderBg(minecraft, xm, ym); + + if (!active) + { + drawCenteredString(font, msg, x + w / 2, y + (h - 8) / 2, 0xffa0a0a0); + } + else + { + if (hovered) + { + drawCenteredString(font, msg, x + w / 2, y + (h - 8) / 2, 0xffffa0); + } + else + { + drawCenteredString(font, msg, x + w / 2, y + (h - 8) / 2, 0xe0e0e0); + } + } + +} + +void Button::renderBg(Minecraft *minecraft, int xm, int ym) +{ +} + +void Button::released(int mx, int my) +{ +} + +bool Button::clicked(Minecraft *minecraft, int mx, int my) +{ + return active && mx >= x && my >= y && mx < x + w && my < y + h; +} \ No newline at end of file diff --git a/Minecraft.Client/Button.h b/Minecraft.Client/Button.h new file mode 100644 index 0000000..0bef133 --- /dev/null +++ b/Minecraft.Client/Button.h @@ -0,0 +1,30 @@ +#pragma once +#include "GuiComponent.h" +using namespace std; + +class Button : public GuiComponent +{ +protected: + int w; + int h; +public: + int x, y; + wstring msg; + int id; + bool active; + bool visible; + + Button(int id, int x, int y, const wstring& msg); + Button(int id, int x, int y, int w, int h, const wstring& msg); + void init(int id, int x, int y, int w, int h, const wstring& msg); // 4J - added +protected: + virtual int getYImage(bool hovered); +public: + virtual void render(Minecraft *minecraft, int xm, int ym); + +protected: + virtual void renderBg(Minecraft *minecraft, int xm, int ym); +public: + virtual void released(int mx, int my); + virtual bool clicked(Minecraft *minecraft, int mx, int my); +}; diff --git a/Minecraft.Client/Camera.cpp b/Minecraft.Client/Camera.cpp new file mode 100644 index 0000000..db6072b --- /dev/null +++ b/Minecraft.Client/Camera.cpp @@ -0,0 +1,124 @@ +#include "stdafx.h" +#include "Camera.h" +#include "MemoryTracker.h" +#include "..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "..\Minecraft.World\net.minecraft.world.level.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\Minecraft.World\TilePos.h" + +float Camera::xPlayerOffs = 0.0f; +float Camera::yPlayerOffs = 0.0f; +float Camera::zPlayerOffs = 0.0f; + +//IntBuffer *Camera::viewport = MemoryTracker::createIntBuffer(16); +FloatBuffer *Camera::modelview = MemoryTracker::createFloatBuffer(16); +FloatBuffer *Camera::projection = MemoryTracker::createFloatBuffer(16); +//FloatBuffer *Camera::position = MemoryTracker::createFloatBuffer(3); + +float Camera::xa = 0.0f; +float Camera::ya = 0.0f; +float Camera::za = 0.0f; +float Camera::xa2 = 0.0f; +float Camera::za2 = 0.0f; + +void Camera::prepare(shared_ptr player, bool mirror) +{ + glGetFloat(GL_MODELVIEW_MATRIX, modelview); + glGetFloat(GL_PROJECTION_MATRIX, projection); + + /* Original java code for reference + glGetInteger(GL_VIEWPORT, viewport); + + float x = (viewport.get(0) + viewport.get(2)) / 2; + float y = (viewport.get(1) + viewport.get(3)) / 2; + gluUnProject(x, y, 0, modelview, projection, viewport, position); + + xPlayerOffs = position->get(0); + yPlayerOffs = position->get(1); + zPlayerOffs = position->get(2); + */ + + // Xbox conversion here... note that we don't bother getting the viewport as this is just working out how to get a (0,0,0) point in clip space to pass into the inverted + // combined model/view/projection matrix, so we just need to get this matrix and get its translation as an equivalent. + XMMATRIX _modelview, _proj, _final, _invert; + XMVECTOR _det; + XMFLOAT4 trans; + + memcpy( &_modelview, modelview->_getDataPointer(), 64 ); + memcpy( &_proj, projection->_getDataPointer(), 64 ); + +#if ( defined __ORBIS__ ) || ( defined __PSVITA__ ) + _modelview = transpose(_modelview); + _proj = transpose(_proj); + _final = _modelview * _proj; + _invert = sce::Vectormath::Simd::Aos::inverse(_final); + xPlayerOffs = _invert.getElem(0,3) / _invert.getElem(3,3); + yPlayerOffs = _invert.getElem(1,3) / _invert.getElem(3,3); + zPlayerOffs = _invert.getElem(2,3) / _invert.getElem(3,3); +#elif defined __PS3__ + _modelview = transpose(_modelview); + _proj = transpose(_proj); + _final = _modelview * _proj; + _invert = Vectormath::Aos::inverse(_final); + xPlayerOffs = _invert.getElem(0,3) / _invert.getElem(3,3); + yPlayerOffs = _invert.getElem(1,3) / _invert.getElem(3,3); + zPlayerOffs = _invert.getElem(2,3) / _invert.getElem(3,3); +#else + _final = XMMatrixMultiply( _modelview, _proj ); + _det = XMMatrixDeterminant(_final); + _invert = XMMatrixInverse(&_det, _final); + + XMStoreFloat4(&trans,_invert.r[3]); + + xPlayerOffs = trans.x / trans.w; + yPlayerOffs = trans.y / trans.w; + zPlayerOffs = trans.z / trans.w; +#endif + + int flipCamera = mirror ? 1 : 0; + + float xRot = player->xRot; + float yRot = player->yRot; + + xa = cosf(yRot * PI / 180.0f) * (1 - flipCamera * 2); + za = sinf(yRot * PI / 180.0f) * (1 - flipCamera * 2); + + xa2 = -za * sinf(xRot * PI / 180.0f) * (1 - flipCamera * 2); + za2 = xa * sinf(xRot * PI / 180.0f) * (1 - flipCamera * 2); + ya = cosf(xRot * PI / 180.0f); +} + +TilePos *Camera::getCameraTilePos(shared_ptr player, double alpha) +{ + return new TilePos(getCameraPos(player, alpha)); +} + +Vec3 *Camera::getCameraPos(shared_ptr player, double alpha) +{ + double xx = player->xo + (player->x - player->xo) * alpha; + double yy = player->yo + (player->y - player->yo) * alpha + player->getHeadHeight(); + double zz = player->zo + (player->z - player->zo) * alpha; + + double xt = xx + Camera::xPlayerOffs * 1; + double yt = yy + Camera::yPlayerOffs * 1; + double zt = zz + Camera::zPlayerOffs * 1; + + return Vec3::newTemp(xt, yt, zt); +} + +int Camera::getBlockAt(Level *level, shared_ptr player, float alpha) +{ + Vec3 *p = Camera::getCameraPos(player, alpha); + TilePos tp = TilePos(p); + int t = level->getTile(tp.x, tp.y, tp.z); + if (t != 0 && Tile::tiles[t]->material->isLiquid()) + { + float hh = LiquidTile::getHeight(level->getData(tp.x, tp.y, tp.z)) - 1 / 9.0f; + float h = tp.y + 1 - hh; + if (p->y >= h) + { + t = level->getTile(tp.x, tp.y + 1, tp.z); + } + } + return t; +} \ No newline at end of file diff --git a/Minecraft.Client/Camera.h b/Minecraft.Client/Camera.h new file mode 100644 index 0000000..cccb0b2 --- /dev/null +++ b/Minecraft.Client/Camera.h @@ -0,0 +1,32 @@ +#pragma once +#include "..\Minecraft.World\FloatBuffer.h" +#include "..\Minecraft.World\IntBuffer.h" + + +class TilePos; +class Vec3; +class Player; +class Mob; + +class Camera +{ +public: + static float xPlayerOffs; + static float yPlayerOffs; + static float zPlayerOffs; + +private: +// static IntBuffer *viewport; + static FloatBuffer *modelview; + static FloatBuffer *projection; +// static FloatBuffer *position; + +public: + static float xa, ya, za, xa2, za2; + + static void prepare(shared_ptr player, bool mirror); + + static TilePos *getCameraTilePos(shared_ptr player, double alpha); + static Vec3 *getCameraPos(shared_ptr player, double alpha); + static int getBlockAt(Level *level, shared_ptr player, float alpha); +}; \ No newline at end of file diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp new file mode 100644 index 0000000..b68e6ca --- /dev/null +++ b/Minecraft.Client/ChatScreen.cpp @@ -0,0 +1,89 @@ +#include "stdafx.h" +#include "ChatScreen.h" +#include "MultiplayerLocalPlayer.h" +#include "..\Minecraft.World\SharedConstants.h" +#include "..\Minecraft.World\StringHelpers.h" + +const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters; + +ChatScreen::ChatScreen() +{ + frame = 0; +} + +void ChatScreen::init() +{ + Keyboard::enableRepeatEvents(true); +} + +void ChatScreen::removed() +{ + Keyboard::enableRepeatEvents(false); +} + +void ChatScreen::tick() +{ + frame++; +} + +void ChatScreen::keyPressed(wchar_t ch, int eventKey) +{ + if (eventKey == Keyboard::KEY_ESCAPE) + { + minecraft->setScreen(NULL); + return; + } + if (eventKey == Keyboard::KEY_RETURN) + { + wstring msg = trimString(message); + if (msg.length() > 0) + { + wstring trim = trimString(message); + if (!minecraft->handleClientSideCommand(trim)) + { + minecraft->player->chat(trim); + } + } + minecraft->setScreen(NULL); + return; + } + if (eventKey == Keyboard::KEY_BACK && message.length() > 0) message = message.substr(0, message.length() - 1); + if (allowedChars.find(ch) >= 0 && message.length() < SharedConstants::maxChatLength) + { + message += ch; + } + +} + +void ChatScreen::render(int xm, int ym, float a) +{ + fill(2, height - 14, width - 2, height - 2, 0x80000000); + drawString(font, L"> " + message + (frame / 6 % 2 == 0 ? L"_" : L""), 4, height - 12, 0xe0e0e0); + + Screen::render(xm, ym, a); +} + +void ChatScreen::mouseClicked(int x, int y, int buttonNum) +{ + if (buttonNum == 0) + { + if (minecraft->gui->selectedName != L"") // 4J - was NULL comparison + { + if (message.length() > 0 && message[message.length()-1]!=L' ') + { + message += L" "; + } + message += minecraft->gui->selectedName; + unsigned int maxLength = SharedConstants::maxChatLength; + if (message.length() > maxLength) + { + message = message.substr(0, maxLength); + } + } + else + { + Screen::mouseClicked(x, y, buttonNum); + } + } + +} \ No newline at end of file diff --git a/Minecraft.Client/ChatScreen.h b/Minecraft.Client/ChatScreen.h new file mode 100644 index 0000000..d715847 --- /dev/null +++ b/Minecraft.Client/ChatScreen.h @@ -0,0 +1,25 @@ +#pragma once +#include "Screen.h" +using namespace std; + +class ChatScreen : public Screen +{ +protected: + wstring message; +private: + int frame; + +public: + ChatScreen(); //4J added + virtual void init(); + virtual void removed(); + virtual void tick(); +private: + static const wstring allowedChars; +protected: + void keyPressed(wchar_t ch, int eventKey); +public: + void render(int xm, int ym, float a); +protected: + void mouseClicked(int x, int y, int buttonNum); +}; \ No newline at end of file diff --git a/Minecraft.Client/ChestModel.cpp b/Minecraft.Client/ChestModel.cpp new file mode 100644 index 0000000..63f27c4 --- /dev/null +++ b/Minecraft.Client/ChestModel.cpp @@ -0,0 +1,43 @@ +#include "stdafx.h" +#include "ChestModel.h" +#include "ModelPart.h" + +ChestModel::ChestModel() +{ + lid = ((new ModelPart(this, 0, 0)))->setTexSize(64, 64); + lid->addBox(0.0f, -5.0f, -14.0f, 14, 5, 14, 0.0f); + lid->x = 1; + lid->y = 7; + lid->z = 15; + + lock = ((new ModelPart(this, 0, 0)))->setTexSize(64, 64); + lock->addBox(-1.0f, -2.0f, -15.0f, 2, 4, 1, 0.0f); + lock->x = 8; + lock->y = 7; + lock->z = 15; + + bottom = ((new ModelPart(this, 0, 19)))->setTexSize(64, 64); + bottom->addBox(0.0f, 0.0f, 0.0f, 14, 10, 14, 0.0f); + bottom->x = 1; + bottom->y = 6; + bottom->z = 1; + + + // 4J added - compile now to avoid random performance hit first time cubes are rendered + lid->compile(1.0f/16.0f); + lock->compile(1.0f/16.0f); + bottom->compile(1.0f/16.0f); +} + +void ChestModel::render(bool usecompiled) +{ + lock->xRot = lid->xRot; + + lock->render(1 / 16.0f, usecompiled); + bottom->render(1 / 16.0f, usecompiled); + + // 4J - moved lid to last and added z-bias to avoid glitching caused by z-fighting between the area of overlap between the lid & bottom of the chest + glPolygonOffset(-0.3f, -0.3f); + lid->render(1 / 16.0f, usecompiled); + glPolygonOffset(0.0f, 0.0f); +} \ No newline at end of file diff --git a/Minecraft.Client/ChestModel.h b/Minecraft.Client/ChestModel.h new file mode 100644 index 0000000..416ccf7 --- /dev/null +++ b/Minecraft.Client/ChestModel.h @@ -0,0 +1,18 @@ +#pragma once + +#include "Model.h" + +class Cube; + +class ChestModel : public Model +{ +public: + using Model::render; + + ModelPart *lid; + ModelPart *bottom; + ModelPart *lock; + + ChestModel(); + void render(bool usecompiled); +}; diff --git a/Minecraft.Client/ChestRenderer.cpp b/Minecraft.Client/ChestRenderer.cpp new file mode 100644 index 0000000..d1b5cf9 --- /dev/null +++ b/Minecraft.Client/ChestRenderer.cpp @@ -0,0 +1,105 @@ +#include "stdafx.h" +#include "ChestRenderer.h" +#include "ChestModel.h" +#include "LargeChestModel.h" +#include "ModelPart.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.h" + +ChestRenderer::ChestRenderer() +{ + chestModel = new ChestModel(); + largeChestModel = new LargeChestModel(); +} + +ChestRenderer::~ChestRenderer() +{ + delete chestModel; + delete largeChestModel; +} + +void ChestRenderer::render(shared_ptr _chest, double x, double y, double z, float a, bool setColor, float alpha, bool useCompiled) +{ + // 4J Convert as we aren't using a templated class + shared_ptr chest = dynamic_pointer_cast(_chest); + + int data; + + if (!chest->hasLevel()) + { + data = 0; + } + else + { + Tile *tile = chest->getTile(); + data = chest->getData(); + + if (tile != NULL && data == 0) + { + ((ChestTile *) tile)->recalcLockDir(chest->getLevel(), chest->x, chest->y, chest->z); + data = chest->getData(); + } + + chest->checkNeighbors(); + } + if (chest->n.lock() != NULL || chest->w.lock() != NULL) return; + + + ChestModel *model; + if (chest->e.lock() != NULL || chest->s.lock() != NULL) + { + model = largeChestModel; + bindTexture(TN_TILE_LARGE_CHEST); // 4J Was "/item/largechest.png" + } + else + { + model = chestModel; + bindTexture(TN_TILE_CHEST); // 4J Was "/item/chest.png" + } + + glPushMatrix(); + glEnable(GL_RESCALE_NORMAL); + //if( setColor ) glColor4f(1, 1, 1, 1); + if( setColor ) glColor4f(1, 1, 1, alpha); + glTranslatef((float) x, (float) y + 1, (float) z + 1); + glScalef(1, -1, -1); + + glTranslatef(0.5f, 0.5f, 0.5f); + int rot = 0; + if (data == 2) rot = 180; + if (data == 3) rot = 0; + if (data == 4) rot = 90; + if (data == 5) rot = -90; + + if (data == 2 && chest->e.lock() != NULL) + { + glTranslatef(1, 0, 0); + } + if (data == 5 && chest->s.lock() != NULL) + { + glTranslatef(0, 0, -1); + } + glRotatef(rot, 0, 1, 0); + glTranslatef(-0.5f, -0.5f, -0.5f); + + float open = chest->oOpenness + (chest->openness - chest->oOpenness) * a; + if (chest->n.lock() != NULL) + { + float open2 = chest->n.lock()->oOpenness + (chest->n.lock()->openness - chest->n.lock()->oOpenness) * a; + if (open2 > open) open = open2; + } + if (chest->w.lock() != NULL) + { + float open2 = chest->w.lock()->oOpenness + (chest->w.lock()->openness - chest->w.lock()->oOpenness) * a; + if (open2 > open) open = open2; + } + + open = 1 - open; + open = 1 - open * open * open; + + model->lid->xRot = -(open * PI / 2); + model->render(useCompiled); + glDisable(GL_RESCALE_NORMAL); + glPopMatrix(); + if( setColor ) glColor4f(1, 1, 1, 1); +} diff --git a/Minecraft.Client/ChestRenderer.h b/Minecraft.Client/ChestRenderer.h new file mode 100644 index 0000000..06c6bff --- /dev/null +++ b/Minecraft.Client/ChestRenderer.h @@ -0,0 +1,18 @@ +#pragma once + +#include "TileEntityRenderer.h" + +class ChestModel; + +class ChestRenderer : public TileEntityRenderer +{ +private: + ChestModel *chestModel; + ChestModel *largeChestModel; + +public: + ChestRenderer(); + ~ChestRenderer(); + + void render(shared_ptr _chest, double x, double y, double z, float a, bool setColor, float alpha=1.0f, bool useCompiled = true); // 4J added setColor param +}; diff --git a/Minecraft.Client/ChickenModel.cpp b/Minecraft.Client/ChickenModel.cpp new file mode 100644 index 0000000..21dc205 --- /dev/null +++ b/Minecraft.Client/ChickenModel.cpp @@ -0,0 +1,104 @@ +#include "stdafx.h" +#include "..\Minecraft.World\Mth.h" +#include "ChickenModel.h" +#include "ModelPart.h" + +ChickenModel::ChickenModel() : Model() +{ + int yo = 16; + head = new ModelPart(this, 0, 0); + head->addBox(-2.0f, -6.0f, -2.0f, 4, 6, 3, 0.0f); // Head + head->setPos(0, (float)(-1 + yo), -4); + + beak = new ModelPart(this, 14, 0); + beak->addBox(-2.0f, -4.0f, -4.0f, 4, 2, 2, 0.0f); // Beak + beak->setPos(0, (float)(-1 + yo), -4); + + redThing = new ModelPart(this, 14, 4); + redThing->addBox(-1.0f, -2.0f, -3.0f, 2, 2, 2, 0.0f); // Beak + redThing->setPos(0, (float)(-1 + yo), -4); + + body = new ModelPart(this, 0, 9); + body->addBox(-3.0f, -4.0f, -3.0f, 6, 8, 6, 0.0f); // Body + body->setPos(0, (float)(0 + yo), 0); + + leg0 = new ModelPart(this, 26, 0); + leg0->addBox(-1.0f, 0.0f, -3.0f, 3, 5, 3); // Leg0 + leg0->setPos(-2, (float)(3 + yo), 1); + + leg1 = new ModelPart(this, 26, 0); + leg1->addBox(-1.0f, 0.0f, -3.0f, 3, 5, 3); // Leg1 + leg1->setPos(1, (float)(3 + yo), 1); + + wing0 = new ModelPart(this, 24, 13); + wing0->addBox(0.0f, 0.0f, -3.0f, 1, 4, 6); // Wing0 + wing0->setPos(-4, (float)(-3 + yo), 0); + + wing1 = new ModelPart(this, 24, 13); + wing1->addBox(-1.0f, 0.0f, -3.0f, 1, 4, 6); // Wing1 + wing1->setPos(4, (float)(-3 + yo), 0); + + // 4J added - compile now to avoid random performance hit first time cubes are rendered + head->compile(1.0f/16.0f); + beak->compile(1.0f/16.0f); + redThing->compile(1.0f/16.0f); + body->compile(1.0f/16.0f); + leg0->compile(1.0f/16.0f); + leg1->compile(1.0f/16.0f); + wing0->compile(1.0f/16.0f); + wing1->compile(1.0f/16.0f); +} + +void ChickenModel::render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled) +{ + setupAnim(time, r, bob, yRot, xRot, scale); + if (young) + { + float ss = 2; + glPushMatrix(); + glTranslatef(0, 5 * scale, 2 * scale); + head->render(scale,usecompiled); + beak->render(scale,usecompiled); + redThing->render(scale,usecompiled); + glPopMatrix(); + glPushMatrix(); + glScalef(1 / ss, 1 / ss, 1 / ss); + glTranslatef(0, 24 * scale, 0); + body->render(scale,usecompiled); + leg0->render(scale,usecompiled); + leg1->render(scale,usecompiled); + wing0->render(scale,usecompiled); + wing1->render(scale,usecompiled); + glPopMatrix(); + } + else + { + head->render(scale,usecompiled); + beak->render(scale,usecompiled); + redThing->render(scale,usecompiled); + body->render(scale,usecompiled); + leg0->render(scale,usecompiled); + leg1->render(scale,usecompiled); + wing0->render(scale,usecompiled); + wing1->render(scale,usecompiled); + } +} + +void ChickenModel::setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim) +{ + head->xRot = xRot / (float) (180 / PI); + head->yRot = yRot / (float) (180 / PI); + + beak->xRot = head->xRot; + beak->yRot = head->yRot; + + redThing->xRot = head->xRot; + redThing->yRot = head->yRot; + + body->xRot = 90 / (float) (180 / PI); + + leg0->xRot = (Mth::cos(time * 0.6662f) * 1.4f) * r; + leg1->xRot = ( Mth::cos(time * 0.6662f + PI) * 1.4f) * r; + wing0->zRot = bob; + wing1->zRot = -bob; +} diff --git a/Minecraft.Client/ChickenModel.h b/Minecraft.Client/ChickenModel.h new file mode 100644 index 0000000..9ee0858 --- /dev/null +++ b/Minecraft.Client/ChickenModel.h @@ -0,0 +1,11 @@ +#include "Model.h" + +class ChickenModel : public Model +{ +public: + ModelPart *head, *hair, *body, *leg0, *leg1, *wing0,* wing1, *beak, *redThing; + + ChickenModel(); + virtual void render(shared_ptr entity, float time, float r, float bob, float yRot, float xRot, float scale, bool usecompiled); + virtual void setupAnim(float time, float r, float bob, float yRot, float xRot, float scale, unsigned int uiBitmaskOverrideAnim=0); +}; diff --git a/Minecraft.Client/ChickenRenderer.cpp b/Minecraft.Client/ChickenRenderer.cpp new file mode 100644 index 0000000..908ba50 --- /dev/null +++ b/Minecraft.Client/ChickenRenderer.cpp @@ -0,0 +1,24 @@ +#include "stdafx.h" +#include "..\Minecraft.World\Mth.h" +#include "ChickenRenderer.h" +#include "..\Minecraft.World\net.minecraft.world.entity.animal.h" + +ChickenRenderer::ChickenRenderer(Model *model, float shadow) : MobRenderer(model,shadow) +{ +} + +void ChickenRenderer::render(shared_ptr _mob, double x, double y, double z, float rot, float a) +{ + MobRenderer::render(_mob, x, y, z, rot, a); +} + +float ChickenRenderer::getBob(shared_ptr _mob, float a) +{ + // 4J - dynamic cast required because we aren't using templates/generics in our version + shared_ptr mob = dynamic_pointer_cast(_mob); + + float flap = mob->oFlap+(mob->flap-mob->oFlap)*a; + float flapSpeed = mob->oFlapSpeed+(mob->flapSpeed-mob->oFlapSpeed)*a; + + return (Mth::sin(flap)+1)*flapSpeed; +} \ No newline at end of file diff --git a/Minecraft.Client/ChickenRenderer.h b/Minecraft.Client/ChickenRenderer.h new file mode 100644 index 0000000..b81c913 --- /dev/null +++ b/Minecraft.Client/ChickenRenderer.h @@ -0,0 +1,11 @@ +#pragma once +#include "MobRenderer.h" + +class ChickenRenderer : public MobRenderer +{ +public: + ChickenRenderer(Model *model, float shadow); + virtual void render(shared_ptr _mob, double x, double y, double z, float rot, float a); +protected: + virtual float getBob(shared_ptr _mob, float a); +}; \ No newline at end of file diff --git a/Minecraft.Client/Chunk.cpp b/Minecraft.Client/Chunk.cpp new file mode 100644 index 0000000..99933db --- /dev/null +++ b/Minecraft.Client/Chunk.cpp @@ -0,0 +1,1045 @@ +#include "stdafx.h" +#include "Chunk.h" +#include "TileRenderer.h" +#include "TileEntityRenderDispatcher.h" +#include "..\Minecraft.World\net.minecraft.world.level.h" +#include "..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "LevelRenderer.h" + +#ifdef __PS3__ +#include "PS3\SPU_Tasks\ChunkUpdate\ChunkRebuildData.h" +#include "PS3\SPU_Tasks\ChunkUpdate\TileRenderer_SPU.h" +#include "PS3\SPU_Tasks\CompressedTile\CompressedTileStorage_SPU.h" + +#include "C4JThread_SPU.h" +#include "C4JSpursJob.h" +#endif + +int Chunk::updates = 0; + +#ifdef _LARGE_WORLDS +DWORD Chunk::tlsIdx = TlsAlloc(); + +void Chunk::CreateNewThreadStorage() +{ + unsigned char *tileIds = new unsigned char[16 * 16 * Level::maxBuildHeight]; + TlsSetValue(tlsIdx, tileIds); +} + +void Chunk::ReleaseThreadStorage() +{ + unsigned char *tileIds = (unsigned char *)TlsGetValue(tlsIdx); + delete tileIds; +} + +unsigned char *Chunk::GetTileIdsStorage() +{ + unsigned char *tileIds = (unsigned char *)TlsGetValue(tlsIdx); + return tileIds; +} +#else +// 4J Stu - Don't want this when multi-threaded +Tesselator *Chunk::t = Tesselator::getInstance(); +#endif +LevelRenderer *Chunk::levelRenderer; + +// TODO - 4J see how input entity vector is set up and decide what way is best to pass this to the function +Chunk::Chunk(Level *level, LevelRenderer::rteMap &globalRenderableTileEntities, CRITICAL_SECTION& globalRenderableTileEntities_cs, int x, int y, int z, ClipChunk *clipChunk) + : globalRenderableTileEntities( &globalRenderableTileEntities ), globalRenderableTileEntities_cs(&globalRenderableTileEntities_cs) +{ + clipChunk->visible = false; + bb = NULL; + id = 0; + + this->level = level; + //this->globalRenderableTileEntities = globalRenderableTileEntities; + + assigned = false; + this->clipChunk = clipChunk; + setPos(x, y, z); +} + +void Chunk::setPos(int x, int y, int z) +{ + if(assigned && (x == this->x && y == this->y && z == this->z)) return; + + reset(); + + this->x = x; + this->y = y; + this->z = z; + xm = x + XZSIZE / 2; + ym = y + SIZE / 2; + zm = z + XZSIZE / 2; + clipChunk->xm = xm; + clipChunk->ym = ym; + clipChunk->zm = zm; + + clipChunk->globalIdx = LevelRenderer::getGlobalIndexForChunk(x, y, z, level); + +#if 1 + // 4J - we're not using offsetted renderlists anymore, so just set the full position of this chunk into x/y/zRenderOffs where + // it will be used directly in the renderlist of this chunk + xRenderOffs = x; + yRenderOffs = y; + zRenderOffs = z; + xRender = 0; + yRender = 0; + zRender = 0; +#else + xRenderOffs = x & 1023; + yRenderOffs = y; + zRenderOffs = z & 1023; + xRender = x - xRenderOffs; + yRender = y - yRenderOffs; + zRender = z - zRenderOffs; +#endif + + float g = 6.0f; + // 4J - changed to just set the value rather than make a new one, if we've already created storage + if( bb == NULL ) + { + bb = AABB::newPermanent(-g, -g, -g, XZSIZE+g, SIZE+g, XZSIZE+g); + } + else + { + // 4J MGH - bounds are relative to the position now, so the AABB will be setup already, either above, or from the tesselator bounds. +// bb->set(-g, -g, -g, SIZE+g, SIZE+g, SIZE+g); + } + clipChunk->aabb[0] = bb->x0 + x; + clipChunk->aabb[1] = bb->y0 + y; + clipChunk->aabb[2] = bb->z0 + z; + clipChunk->aabb[3] = bb->x1 + x; + clipChunk->aabb[4] = bb->y1 + y; + clipChunk->aabb[5] = bb->z1 + z; + + assigned = true; + + EnterCriticalSection(&levelRenderer->m_csDirtyChunks); + unsigned char refCount = levelRenderer->incGlobalChunkRefCount(x, y, z, level); +// printf("\t\t [inc] refcount %d at %d, %d, %d\n",refCount,x,y,z); + +// int idx = levelRenderer->getGlobalIndexForChunk(x, y, z, level); + + // If we're the first thing to be referencing this, mark it up as dirty to get rebuilt + if( refCount == 1 ) + { +// printf("Setting %d %d %d dirty [%d]\n",x,y,z, idx); + // Chunks being made dirty in this way can be very numerous (eg the full visible area of the world at start up, or a whole edge of the world when moving). + // On account of this, don't want to stick them into our lock free queue that we would normally use for letting the render update thread know about this chunk. + // Instead, just set the flag to say this is dirty, and then pass a special value of 1 through to the lock free stack which lets that thread know that at least + // one chunk other than the ones in the stack itself have been made dirty. + levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_DIRTY ); +#ifdef _XBOX + PIXSetMarker(0,"Non-stack event pushed"); +#else + PIXSetMarkerDeprecated(0,"Non-stack event pushed"); +#endif + } + + LeaveCriticalSection(&levelRenderer->m_csDirtyChunks); + + +} + +void Chunk::translateToPos() +{ + glTranslatef((float)xRenderOffs, (float)yRenderOffs, (float)zRenderOffs); +} + + +Chunk::Chunk() +{ +} + +void Chunk::makeCopyForRebuild(Chunk *source) +{ + this->level = source->level; + this->x = source->x; + this->y = source->y; + this->z = source->z; + this->xRender = source->xRender; + this->yRender = source->yRender; + this->zRender = source->zRender; + this->xRenderOffs = source->xRenderOffs; + this->yRenderOffs = source->yRenderOffs; + this->zRenderOffs = source->zRenderOffs; + this->xm = source->xm; + this->ym = source->ym; + this->zm = source->zm; + this->bb = source->bb; + this->clipChunk = NULL; + this->id = source->id; + this->globalRenderableTileEntities = source->globalRenderableTileEntities; + this->globalRenderableTileEntities_cs = source->globalRenderableTileEntities_cs; +} + +void Chunk::rebuild() +{ + PIXBeginNamedEvent(0,"Rebuilding chunk %d, %d, %d", x, y, z); +#if defined __PS3__ && !defined DISABLE_SPU_CODE + rebuild_SPU(); + return; +#endif // __PS3__ + +// if (!dirty) return; + PIXBeginNamedEvent(0,"Rebuild section A"); + +#ifdef _LARGE_WORLDS + Tesselator *t = Tesselator::getInstance(); +#else + Chunk::t = Tesselator::getInstance(); // 4J - added - static initialiser being set at the wrong time +#endif + + updates++; + + int x0 = x; + int y0 = y; + int z0 = z; + int x1 = x + XZSIZE; + int y1 = y + SIZE; + int z1 = z + XZSIZE; + + LevelChunk::touchedSky = false; + +// unordered_set > oldTileEntities(renderableTileEntities.begin(),renderableTileEntities.end()); // 4J removed this & next line +// renderableTileEntities.clear(); + + vector > renderableTileEntities; // 4J - added + + int r = 1; + + int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2; + lists += levelRenderer->chunkLists; + + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Rebuild section B"); + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // 4J - optimisation begins. + + // Get the data for the level chunk that this render chunk is it (level chunk is 16 x 16 x 128, + // render chunk is 16 x 16 x 16. We wouldn't have to actually get all of it if the data was ordered differently, but currently + // it is ordered by x then z then y so just getting a small range of y out of it would involve getting the whole thing into + // the cache anyway. + +#ifdef _LARGE_WORLDS + unsigned char *tileIds = GetTileIdsStorage(); +#else + static unsigned char tileIds[16 * 16 * Level::maxBuildHeight]; +#endif + byteArray tileArray = byteArray(tileIds, 16 * 16 * Level::maxBuildHeight); + level->getChunkAt(x,z)->getBlockData(tileArray); // 4J - TODO - now our data has been re-arranged, we could just extra the vertical slice of this chunk rather than the whole thing + + LevelSource *region = new Region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r); + TileRenderer *tileRenderer = new TileRenderer(region, this->x, this->y, this->z, tileIds); + + // AP - added a caching system for Chunk::rebuild to take advantage of + // Basically we're storing of copy of the tileIDs array inside the region so that calls to Region::getTile can grab data + // more quickly from this array rather than calling CompressedTileStorage. On the Vita the total thread time spent in + // Region::getTile went from 20% to 4%. +#ifdef __PSVITA__ + int xc = x >> 4; + int zc = z >> 4; + ((Region*)region)->setCachedTiles(tileIds, xc, zc); +#endif + + // We now go through the vertical section of this level chunk that we are interested in and try and establish + // (1) if it is completely empty + // (2) if any of the tiles can be quickly determined to not need rendering because they are in the middle of other tiles and + // so can't be seen. A large amount (> 60% in tests) of tiles that call tesselateInWorld in the unoptimised version + // of this function fall into this category. By far the largest category of these are tiles in solid regions of rock. + bool empty = true; + for( int yy = y0; yy < y1; yy++ ) + { + for( int zz = 0; zz < 16; zz++ ) + { + for( int xx = 0; xx < 16; xx++ ) + { + // 4J Stu - tile data is ordered in 128 blocks of full width, lower 128 then upper 128 + int indexY = yy; + int offset = 0; + if(indexY >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + indexY -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + offset = Level::COMPRESSED_CHUNK_SECTION_TILES; + } + + unsigned char tileId = tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 ) ) ]; + if( tileId > 0 ) empty = false; + + // Don't bother trying to work out neighbours for this tile if we are at the edge of the chunk - apart from the very + // bottom of the world where we shouldn't ever be able to see + if( yy == (Level::maxBuildHeight - 1) ) continue; + if(( xx == 0 ) || ( xx == 15 )) continue; + if(( zz == 0 ) || ( zz == 15 )) continue; + + // Establish whether this tile and its neighbours are all made of rock, dirt, unbreakable tiles, or have already + // been determined to meet this criteria themselves and have a tile of 255 set. + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + tileId = tileIds[ offset + ( ( ( xx - 1 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 )) ]; + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + tileId = tileIds[ offset + ( ( ( xx + 1 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 )) ]; + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + tileId = tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz - 1 ) << 7 ) | ( indexY + 0 )) ]; + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + tileId = tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 1 ) << 7 ) | ( indexY + 0 )) ]; + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + // Treat the bottom of the world differently - we shouldn't ever be able to look up at this, so consider tiles as invisible + // if they are surrounded on sides other than the bottom + if( yy > 0 ) + { + int indexYMinusOne = yy - 1; + int yMinusOneOffset = 0; + if(indexYMinusOne >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + indexYMinusOne -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + yMinusOneOffset = Level::COMPRESSED_CHUNK_SECTION_TILES; + } + tileId = tileIds[ yMinusOneOffset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | indexYMinusOne ) ]; + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + } + int indexYPlusOne = yy + 1; + int yPlusOneOffset = 0; + if(indexYPlusOne >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + indexYPlusOne -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + yPlusOneOffset = Level::COMPRESSED_CHUNK_SECTION_TILES; + } + tileId = tileIds[ yPlusOneOffset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | indexYPlusOne ) ]; + if( !( ( tileId == Tile::rock_Id ) || ( tileId == Tile::dirt_Id ) || ( tileId == Tile::unbreakable_Id ) || ( tileId == 255) ) ) continue; + + // This tile is surrounded. Flag it as not requiring to be rendered by setting its id to 255. + tileIds[ offset + ( ( ( xx + 0 ) << 11 ) | ( ( zz + 0 ) << 7 ) | ( indexY + 0 ) ) ] = 0xff; + } + } + } + PIXEndNamedEvent(); + // Nothing at all to do for this chunk? + if( empty ) + { + // 4J - added - clear any renderer data associated with this + for (int currentLayer = 0; currentLayer < 2; currentLayer++) + { + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + RenderManager.CBuffClear(lists + currentLayer); + } + + delete region; + delete tileRenderer; + return; + } + // 4J - optimisation ends + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + PIXBeginNamedEvent(0,"Rebuild section C"); + Tesselator::Bounds bounds; // 4J MGH - added + { + // this was the old default clip bounds for the chunk, set in Chunk::setPos. + float g = 6.0f; + bounds.boundingBox[0] = -g; + bounds.boundingBox[1] = -g; + bounds.boundingBox[2] = -g; + bounds.boundingBox[3] = XZSIZE+g; + bounds.boundingBox[4] = SIZE+g; + bounds.boundingBox[5] = XZSIZE+g; + } + for (int currentLayer = 0; currentLayer < 2; currentLayer++) + { + bool renderNextLayer = false; + bool rendered = false; + + bool started = false; + + // 4J - changed loop order here to leave y as the innermost loop for better cache performance + for (int z = z0; z < z1; z++) + { + for (int x = x0; x < x1; x++) + { + for (int y = y0; y < y1; y++) + { + // 4J Stu - tile data is ordered in 128 blocks of full width, lower 128 then upper 128 + int indexY = y; + int offset = 0; + if(indexY >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + indexY -= Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + offset = Level::COMPRESSED_CHUNK_SECTION_TILES; + } + + // 4J - get tile from those copied into our local array in earlier optimisation + unsigned char tileId = tileIds[ offset + ( ( ( x - x0 ) << 11 ) | ( ( z - z0 ) << 7 ) | indexY) ]; + // If flagged as not visible, drop out straight away + if( tileId == 0xff ) continue; +// int tileId = region->getTile(x,y,z); + if (tileId > 0) + { + if (!started) + { + started = true; + + MemSect(31); + glNewList(lists + currentLayer, GL_COMPILE); + MemSect(0); + glPushMatrix(); + glDepthMask(true); // 4J added + t->useCompactVertices(true); // 4J added + translateToPos(); + float ss = 1.000001f; + // 4J - have removed this scale as I don't think we should need it, and have now optimised the vertex + // shader so it doesn't do anything other than translate with this matrix anyway +#if 0 + glTranslatef(-zs / 2.0f, -ys / 2.0f, -zs / 2.0f); + glScalef(ss, ss, ss); + glTranslatef(zs / 2.0f, ys / 2.0f, zs / 2.0f); +#endif + t->begin(); + t->offset((float)(-this->x), (float)(-this->y), (float)(-this->z)); + } + + Tile *tile = Tile::tiles[tileId]; + if (currentLayer == 0 && tile->isEntityTile()) + { + shared_ptr et = region->getTileEntity(x, y, z); + if (TileEntityRenderDispatcher::instance->hasRenderer(et)) + { + renderableTileEntities.push_back(et); + } + } + int renderLayer = tile->getRenderLayer(); + + if (renderLayer != currentLayer) + { + renderNextLayer = true; + } + else if (renderLayer == currentLayer) + { + rendered |= tileRenderer->tesselateInWorld(tile, x, y, z); + } + } + } + } + } + +#ifdef __PSVITA__ + if( currentLayer==0 ) + { + levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_CUT_OUT); + } +#endif + + if (started) + { +#ifdef __PSVITA__ + // AP - make sure we don't attempt to render chunks without cutout geometry + if( t->getCutOutFound() ) + { + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_CUT_OUT); + } +#endif + t->end(); + bounds.addBounds(t->bounds); // 4J MGH - added + glPopMatrix(); + glEndList(); + t->useCompactVertices(false); // 4J added + t->offset(0, 0, 0); + } + else + { + rendered = false; + } + + if (rendered) + { + levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + } + else + { + // 4J - added - clear any renderer data associated with this unused list + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + RenderManager.CBuffClear(lists + currentLayer); + } + if((currentLayer==0)&&(!renderNextLayer)) + { + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY1); + RenderManager.CBuffClear(lists + 1); + break; + } + } + + // 4J MGH - added this to take the bound from the value calc'd in the tesselator + if( bb ) + { + bb->set(bounds.boundingBox[0], bounds.boundingBox[1], bounds.boundingBox[2], + bounds.boundingBox[3], bounds.boundingBox[4], bounds.boundingBox[5]); + } + + delete tileRenderer; + delete region; + + PIXEndNamedEvent(); + PIXBeginNamedEvent(0,"Rebuild section D"); + + // 4J - have rewritten the way that tile entities are stored globally to make it work more easily with split screen. Chunks are now + // stored globally in the levelrenderer, in a hashmap with a special key made up from the dimension and chunk position (using same index + // as is used for global flags) +#if 1 + int key = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level); + EnterCriticalSection(globalRenderableTileEntities_cs); + if( renderableTileEntities.size() ) + { + AUTO_VAR(it, globalRenderableTileEntities->find(key)); + if( it != globalRenderableTileEntities->end() ) + { + // We've got some renderable tile entities that we want associated with this chunk, and an existing list of things that used to be. + // We need to flag any that we don't need any more to be removed, keep those that we do, and add any new ones + + // First pass - flag everything already existing to be removed + for( AUTO_VAR(it2, it->second.begin()); it2 != it->second.end(); it2++ ) + { + (*it2)->setRenderRemoveStage(TileEntity::e_RenderRemoveStageFlaggedAtChunk); + } + + // Now go through the current list. If these are already in the list, then unflag the remove flag. If they aren't, then add + for( int i = 0; i < renderableTileEntities.size(); i++ ) + { + AUTO_VAR(it2, find( it->second.begin(), it->second.end(), renderableTileEntities[i] )); + if( it2 == it->second.end() ) + { + (*globalRenderableTileEntities)[key].push_back(renderableTileEntities[i]); + } + else + { + (*it2)->setRenderRemoveStage(TileEntity::e_RenderRemoveStageKeep); + } + } + } + else + { + // Easy case - nothing already existing for this chunk. Add them all in. + for( int i = 0; i < renderableTileEntities.size(); i++ ) + { + (*globalRenderableTileEntities)[key].push_back(renderableTileEntities[i]); + } + } + } + else + { + // Another easy case - we don't want any renderable tile entities associated with this chunk. Flag all to be removed. + AUTO_VAR(it, globalRenderableTileEntities->find(key)); + if( it != globalRenderableTileEntities->end() ) + { + for( AUTO_VAR(it2, it->second.begin()); it2 != it->second.end(); it2++ ) + { + (*it2)->setRenderRemoveStage(TileEntity::e_RenderRemoveStageFlaggedAtChunk); + } + } + } + LeaveCriticalSection(globalRenderableTileEntities_cs); + PIXEndNamedEvent(); +#else + // Find the removed ones: + + // 4J - original code for this section: + /* + Set newTileEntities = new HashSet(); + newTileEntities.addAll(renderableTileEntities); + newTileEntities.removeAll(oldTileEntities); + globalRenderableTileEntities.addAll(newTileEntities); + + oldTileEntities.removeAll(renderableTileEntities); + globalRenderableTileEntities.removeAll(oldTileEntities); + */ + + + unordered_set > newTileEntities(renderableTileEntities.begin(),renderableTileEntities.end()); + + AUTO_VAR(endIt, oldTileEntities.end()); + for( unordered_set >::iterator it = oldTileEntities.begin(); it != endIt; it++ ) + { + newTileEntities.erase(*it); + } + + // 4J - newTileEntities is now renderableTileEntities with any old ones from oldTileEntitesRemoved (so just new things added) + + EnterCriticalSection(globalRenderableTileEntities_cs); + endIt = newTileEntities.end(); + for( unordered_set >::iterator it = newTileEntities.begin(); it != endIt; it++ ) + { + globalRenderableTileEntities->push_back(*it); + } + + // 4J - All these new things added to globalRenderableTileEntities + + AUTO_VAR(endItRTE, renderableTileEntities.end()); + for( vector >::iterator it = renderableTileEntities.begin(); it != endItRTE; it++ ) + { + oldTileEntities.erase(*it); + } + // 4J - oldTileEntities is now the removed items + vector >::iterator it = globalRenderableTileEntities->begin(); + while( it != globalRenderableTileEntities->end() ) + { + if( oldTileEntities.find(*it) != oldTileEntities.end() ) + { + it = globalRenderableTileEntities->erase(it); + } + else + { + ++it; + } + } + + LeaveCriticalSection(globalRenderableTileEntities_cs); +#endif + + // 4J - These removed items are now also removed from globalRenderableTileEntities + + if( LevelChunk::touchedSky ) + { + levelRenderer->clearGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_NOTSKYLIT); + } + else + { + levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_NOTSKYLIT); + } + levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_COMPILED); + PIXEndNamedEvent(); + return; + +} + + +#ifdef __PS3__ +ChunkRebuildData g_rebuildDataIn __attribute__((__aligned__(16))); +ChunkRebuildData g_rebuildDataOut __attribute__((__aligned__(16))); +TileCompressData_SPU g_tileCompressDataIn __attribute__((__aligned__(16))); +unsigned char* g_tileCompressDataOut = (unsigned char*)&g_rebuildDataIn.m_tileIds; + +#define TILE_RENDER_SPU + + +void RunSPURebuild() +{ + + static C4JSpursJobQueue::Port p("C4JSpursJob_ChunkUpdate"); + C4JSpursJob_CompressedTile tileJob(&g_tileCompressDataIn,g_tileCompressDataOut); + C4JSpursJob_ChunkUpdate chunkJob(&g_rebuildDataIn, &g_rebuildDataOut); + + if(g_rebuildDataIn.m_currentLayer == 0) // only need to create the tiles on the first layer + { + p.submitJob(&tileJob); + p.submitSync(); + } + + p.submitJob(&chunkJob); + p.waitForCompletion(); + + assert(g_rebuildDataIn.m_x0 == g_rebuildDataOut.m_x0); +} + +void Chunk::rebuild_SPU() +{ + +// if (!dirty) return; + Chunk::t = Tesselator::getInstance(); // 4J - added - static initialiser being set at the wrong time + updates++; + + int x0 = x; + int y0 = y; + int z0 = z; + int x1 = x + SIZE; + int y1 = y + SIZE; + int z1 = z + SIZE; + + LevelChunk::touchedSky = false; + +// unordered_set > oldTileEntities(renderableTileEntities.begin(),renderableTileEntities.end()); // 4J removed this & next line +// renderableTileEntities.clear(); + + vector > renderableTileEntities; // 4J - added + +// List newTileEntities = new ArrayList(); +// newTileEntities.clear(); +// renderableTileEntities.clear(); + + int r = 1; + + Region region(level, x0 - r, y0 - r, z0 - r, x1 + r, y1 + r, z1 + r); + TileRenderer tileRenderer(®ion); + + int lists = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level) * 2; + lists += levelRenderer->chunkLists; + + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // 4J - optimisation begins. + + // Get the data for the level chunk that this render chunk is it (level chunk is 16 x 16 x 128, + // render chunk is 16 x 16 x 16. We wouldn't have to actually get all of it if the data was ordered differently, but currently + // it is ordered by x then z then y so just getting a small range of y out of it would involve getting the whole thing into + // the cache anyway. + ChunkRebuildData* pOutData = NULL; + g_rebuildDataIn.buildForChunk(®ion, level, x0, y0, z0); + + Tesselator::Bounds bounds; + { + // this was the old default clip bounds for the chunk, set in Chunk::setPos. + float g = 6.0f; + bounds.boundingBox[0] = -g; + bounds.boundingBox[1] = -g; + bounds.boundingBox[2] = -g; + bounds.boundingBox[3] = SIZE+g; + bounds.boundingBox[4] = SIZE+g; + bounds.boundingBox[5] = SIZE+g; + } + + for (int currentLayer = 0; currentLayer < 2; currentLayer++) + { + bool rendered = false; + + { + glNewList(lists + currentLayer, GL_COMPILE); + MemSect(0); + glPushMatrix(); + glDepthMask(true); // 4J added + t->useCompactVertices(true); // 4J added + translateToPos(); + float ss = 1.000001f; + // 4J - have removed this scale as I don't think we should need it, and have now optimised the vertex + // shader so it doesn't do anything other than translate with this matrix anyway + #if 0 + glTranslatef(-zs / 2.0f, -ys / 2.0f, -zs / 2.0f); + glScalef(ss, ss, ss); + glTranslatef(zs / 2.0f, ys / 2.0f, zs / 2.0f); + #endif + t->begin(); + t->offset((float)(-this->x), (float)(-this->y), (float)(-this->z)); + } + + g_rebuildDataIn.copyFromTesselator(); + intArray_SPU tesselatorArray((unsigned int*)g_rebuildDataIn.m_tesselator.m_PPUArray); + g_rebuildDataIn.m_tesselator._array = &tesselatorArray; + g_rebuildDataIn.m_currentLayer = currentLayer; + #ifdef TILE_RENDER_SPU + g_tileCompressDataIn.setForChunk(®ion, x0, y0, z0); + RunSPURebuild(); + g_rebuildDataOut.storeInTesselator(); + pOutData = &g_rebuildDataOut; + #else + g_rebuildDataIn.disableUnseenTiles(); + TileRenderer_SPU *pTileRenderer = new TileRenderer_SPU(&g_rebuildDataIn); + g_rebuildDataIn.tesselateAllTiles(pTileRenderer); + g_rebuildDataIn.storeInTesselator(); + pOutData = &g_rebuildDataIn; + #endif + if(pOutData->m_flags & ChunkRebuildData::e_flag_Rendered) + rendered = true; + + // 4J - changed loop order here to leave y as the innermost loop for better cache performance + for (int z = z0; z < z1; z++) + { + for (int x = x0; x < x1; x++) + { + for (int y = y0; y < y1; y++) + { + // 4J - get tile from those copied into our local array in earlier optimisation + unsigned char tileId = pOutData->getTile(x,y,z); + if (tileId > 0) + { + if (currentLayer == 0 && Tile::tiles[tileId]->isEntityTile()) + { + shared_ptr et = region.getTileEntity(x, y, z); + if (TileEntityRenderDispatcher::instance->hasRenderer(et)) + { + renderableTileEntities.push_back(et); + } + } + int flags = pOutData->getFlags(x,y,z); + if(flags & ChunkRebuildData::e_flag_SPURenderCodeMissing) + { + + Tile *tile = Tile::tiles[tileId]; + int renderLayer = tile->getRenderLayer(); + + if (renderLayer != currentLayer) + { + // renderNextLayer = true; + } + else if (renderLayer == currentLayer) + { + //if(currentLayer == 0) + // numRenderedLayer0++; + rendered |= tileRenderer.tesselateInWorld(tile, x, y, z); + } + } + } + } + } + } + + + { + t->end(); + bounds.addBounds(t->bounds); + glPopMatrix(); + glEndList(); + t->useCompactVertices(false); // 4J added + t->offset(0, 0, 0); + } + if (rendered) + { + levelRenderer->clearGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + } + else + { + // 4J - added - clear any renderer data associated with this unused list + levelRenderer->setGlobalChunkFlag(this->x, this->y, this->z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, currentLayer); + RenderManager.CBuffClear(lists + currentLayer); + } + + } + + if( bb ) + { + bb->set(bounds.boundingBox[0], bounds.boundingBox[1], bounds.boundingBox[2], + bounds.boundingBox[3], bounds.boundingBox[4], bounds.boundingBox[5]); + } + + + if(pOutData->m_flags & ChunkRebuildData::e_flag_TouchedSky) + LevelChunk::touchedSky = true; + + + // 4J - have rewritten the way that tile entities are stored globally to make it work more easily with split screen. Chunks are now + // stored globally in the levelrenderer, in a hashmap with a special key made up from the dimension and chunk position (using same index + // as is used for global flags) +#if 1 + int key = levelRenderer->getGlobalIndexForChunk(this->x,this->y,this->z,level); + EnterCriticalSection(globalRenderableTileEntities_cs); + if( renderableTileEntities.size() ) + { + AUTO_VAR(it, globalRenderableTileEntities->find(key)); + if( it != globalRenderableTileEntities->end() ) + { + // We've got some renderable tile entities that we want associated with this chunk, and an existing list of things that used to be. + // We need to flag any that we don't need any more to be removed, keep those that we do, and add any new ones + + // First pass - flag everything already existing to be removed + for( AUTO_VAR(it2, it->second.begin()); it2 != it->second.end(); it2++ ) + { + (*it2)->setRenderRemoveStage(TileEntity::e_RenderRemoveStageFlaggedAtChunk); + } + + // Now go through the current list. If these are already in the list, then unflag the remove flag. If they aren't, then add + for( int i = 0; i < renderableTileEntities.size(); i++ ) + { + AUTO_VAR(it2, find( it->second.begin(), it->second.end(), renderableTileEntities[i] )); + if( it2 == it->second.end() ) + { + (*globalRenderableTileEntities)[key].push_back(renderableTileEntities[i]); + } + else + { + (*it2)->setRenderRemoveStage(TileEntity::e_RenderRemoveStageKeep); + } + } + } + else + { + // Easy case - nothing already existing for this chunk. Add them all in. + for( int i = 0; i < renderableTileEntities.size(); i++ ) + { + (*globalRenderableTileEntities)[key].push_back(renderableTileEntities[i]); + } + } + } + else + { + // Another easy case - we don't want any renderable tile entities associated with this chunk. Flag all to be removed. + AUTO_VAR(it, globalRenderableTileEntities->find(key)); + if( it != globalRenderableTileEntities->end() ) + { + for( AUTO_VAR(it2, it->second.begin()); it2 != it->second.end(); it2++ ) + { + (*it2)->setRenderRemoveStage(TileEntity::e_RenderRemoveStageFlaggedAtChunk); + } + } + } + LeaveCriticalSection(globalRenderableTileEntities_cs); +#else + // Find the removed ones: + + // 4J - original code for this section: + /* + Set newTileEntities = new HashSet(); + newTileEntities.addAll(renderableTileEntities); + newTileEntities.removeAll(oldTileEntities); + globalRenderableTileEntities.addAll(newTileEntities); + + oldTileEntities.removeAll(renderableTileEntities); + globalRenderableTileEntities.removeAll(oldTileEntities); + */ + + + unordered_set > newTileEntities(renderableTileEntities.begin(),renderableTileEntities.end()); + + AUTO_VAR(endIt, oldTileEntities.end()); + for( unordered_set >::iterator it = oldTileEntities.begin(); it != endIt; it++ ) + { + newTileEntities.erase(*it); + } + + // 4J - newTileEntities is now renderableTileEntities with any old ones from oldTileEntitesRemoved (so just new things added) + + EnterCriticalSection(globalRenderableTileEntities_cs); + endIt = newTileEntities.end(); + for( unordered_set >::iterator it = newTileEntities.begin(); it != endIt; it++ ) + { + globalRenderableTileEntities.push_back(*it); + } + + // 4J - All these new things added to globalRenderableTileEntities + + AUTO_VAR(endItRTE, renderableTileEntities.end()); + for( vector >::iterator it = renderableTileEntities.begin(); it != endItRTE; it++ ) + { + oldTileEntities.erase(*it); + } + // 4J - oldTileEntities is now the removed items + vector >::iterator it = globalRenderableTileEntities->begin(); + while( it != globalRenderableTileEntities->end() ) + { + if( oldTileEntities.find(*it) != oldTileEntities.end() ) + { + it = globalRenderableTileEntities->erase(it); + } + else + { + ++it; + } + } + + LeaveCriticalSection(globalRenderableTileEntities_cs); +#endif + + // 4J - These removed items are now also removed from globalRenderableTileEntities + + if( LevelChunk::touchedSky ) + { + levelRenderer->clearGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_NOTSKYLIT); + } + else + { + levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_NOTSKYLIT); + } + levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_COMPILED); + return; + +} +#endif // _PS3_ + + +float Chunk::distanceToSqr(shared_ptr player) const +{ + float xd = (float) (player->x - xm); + float yd = (float) (player->y - ym); + float zd = (float) (player->z - zm); + return xd * xd + yd * yd + zd * zd; +} + +float Chunk::squishedDistanceToSqr(shared_ptr player) +{ + float xd = (float) (player->x - xm); + float yd = (float) (player->y - ym) * 2; + float zd = (float) (player->z - zm); + return xd * xd + yd * yd + zd * zd; +} + +void Chunk::reset() +{ + if( assigned ) + { + EnterCriticalSection(&levelRenderer->m_csDirtyChunks); + unsigned char refCount = levelRenderer->decGlobalChunkRefCount(x, y, z, level); + assigned = false; +// printf("\t\t [dec] refcount %d at %d, %d, %d\n",refCount,x,y,z); + if( refCount == 0 ) + { + int lists = levelRenderer->getGlobalIndexForChunk(x, y, z, level) * 2; + if(lists >= 0) + { + lists += levelRenderer->chunkLists; + for (int i = 0; i < 2; i++) + { + // 4J - added - clear any renderer data associated with this unused list + RenderManager.CBuffClear(lists + i); + } + levelRenderer->setGlobalChunkFlags(x, y, z, level, 0); + } + } + LeaveCriticalSection(&levelRenderer->m_csDirtyChunks); + } + + clipChunk->visible = false; +} + +void Chunk::_delete() +{ + reset(); + level = NULL; +} + +int Chunk::getList(int layer) +{ + if (!clipChunk->visible) return -1; + + int lists = levelRenderer->getGlobalIndexForChunk(x, y, z,level) * 2; + lists += levelRenderer->chunkLists; + + bool empty = levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer); + if (!empty) return lists + layer; + return -1; +} + +void Chunk::cull(Culler *culler) +{ + clipChunk->visible = culler->isVisible(bb); +} + +void Chunk::renderBB() +{ +// glCallList(lists + 2); // 4J - removed - TODO put back in +} + +bool Chunk::isEmpty() +{ + if (!levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_COMPILED)) return false; + return levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTYBOTH); +} + +void Chunk::setDirty() +{ + // 4J - not used, but if this starts being used again then we'll need to investigate how best to handle it. + __debugbreak(); + levelRenderer->setGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_DIRTY); +} + +void Chunk::clearDirty() +{ + levelRenderer->clearGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_DIRTY); +#ifdef _CRITICAL_CHUNKS + levelRenderer->clearGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_CRITICAL); +#endif +} + +Chunk::~Chunk() +{ + delete bb; +} + +bool Chunk::emptyFlagSet(int layer) +{ + return levelRenderer->getGlobalChunkFlag(x, y, z, level, LevelRenderer::CHUNK_FLAG_EMPTY0, layer); +} diff --git a/Minecraft.Client/Chunk.h b/Minecraft.Client/Chunk.h new file mode 100644 index 0000000..f794715 --- /dev/null +++ b/Minecraft.Client/Chunk.h @@ -0,0 +1,87 @@ +#pragma once +#include "AllowAllCuller.h" +#include "Tesselator.h" +#include "..\Minecraft.World\ArrayWithLength.h" +#include "LevelRenderer.h" + +class Level; +class TileEntity; +class Entity; +using namespace std; + +class ClipChunk +{ +public: + Chunk *chunk; + int globalIdx; + bool visible; + float aabb[6]; + int xm, ym, zm; +}; + +class Chunk +{ +private: + static const int XZSIZE = LevelRenderer::CHUNK_XZSIZE; + static const int SIZE = LevelRenderer::CHUNK_SIZE; + +public: + Level *level; + static LevelRenderer *levelRenderer; +private: +#ifndef _LARGE_WORLDS + static Tesselator *t; +#else + static DWORD tlsIdx; +public: + static void CreateNewThreadStorage(); + static void ReleaseThreadStorage(); + static unsigned char *GetTileIdsStorage(); +#endif + +public: + static int updates; + + int x, y, z; + int xRender, yRender, zRender; + int xRenderOffs, yRenderOffs, zRenderOffs; + + int xm, ym, zm; + AABB *bb; + ClipChunk *clipChunk; + + int id; +//public: +// vector > renderableTileEntities; // 4J - removed + +private: + LevelRenderer::rteMap *globalRenderableTileEntities; + CRITICAL_SECTION *globalRenderableTileEntities_cs; + bool assigned; +public: + Chunk(Level *level, LevelRenderer::rteMap &globalRenderableTileEntities, CRITICAL_SECTION &globalRenderableTileEntities_cs, int x, int y, int z, ClipChunk *clipChunk); + Chunk(); + + void setPos(int x, int y, int z); +private: + void translateToPos(); +public: + void makeCopyForRebuild(Chunk *source); + void rebuild(); +#ifdef __PS3__ + void rebuild_SPU(); +#endif // __PS3__ + float distanceToSqr(shared_ptr player) const; + float squishedDistanceToSqr(shared_ptr player); + void reset(); + void _delete(); + + int getList(int layer); + void cull(Culler *culler); + void renderBB() ; + bool isEmpty(); + void setDirty(); + void clearDirty(); // 4J added + bool emptyFlagSet(int layer); + ~Chunk(); +}; diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp new file mode 100644 index 0000000..b80eaed --- /dev/null +++ b/Minecraft.Client/ClientConnection.cpp @@ -0,0 +1,3347 @@ +#include "stdafx.h" +#include "ClientConnection.h" +#include "MultiPlayerLevel.h" +#include "MultiPlayerLocalPlayer.h" +#include "StatsCounter.h" +#include "ReceivingLevelScreen.h" +#include "RemotePlayer.h" +#include "DisconnectedScreen.h" +#include "TakeAnimationParticle.h" +#include "CritParticle.h" +#include "User.h" +#include "..\Minecraft.World\net.minecraft.world.level.storage.h" +#include "..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\Minecraft.World\net.minecraft.stats.h" +#include "..\Minecraft.World\net.minecraft.world.entity.h" +#include "..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "..\Minecraft.World\net.minecraft.world.entity.npc.h" +#include "..\Minecraft.World\net.minecraft.world.entity.item.h" +#include "..\Minecraft.World\net.minecraft.world.entity.projectile.h" +#include "..\Minecraft.World\net.minecraft.world.entity.global.h" +#include "..\Minecraft.World\net.minecraft.world.entity.boss.enderdragon.h" +#include "..\Minecraft.World\net.minecraft.world.entity.monster.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\Minecraft.World\net.minecraft.world.item.h" +#include "..\Minecraft.World\net.minecraft.world.item.trading.h" +#include "..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\Minecraft.World\net.minecraft.world.h" +#include "..\Minecraft.World\net.minecraft.world.level.saveddata.h" +#include "..\Minecraft.World\net.minecraft.world.level.dimension.h" +#include "..\Minecraft.World\net.minecraft.world.effect.h" +#include "..\Minecraft.World\net.minecraft.world.food.h" +#include "..\Minecraft.World\SharedConstants.h" +#include "..\Minecraft.World\AABB.h" +#include "..\Minecraft.World\Pos.h" +#include "..\Minecraft.World\Socket.h" +#include "Minecraft.h" +#include "ProgressRenderer.h" +#include "LevelRenderer.h" +#include "Options.h" +#include "MinecraftServer.h" +#include "ClientConstants.h" +#include "..\Minecraft.World\SoundTypes.h" +#include "TexturePackRepository.h" +#ifdef _XBOX +#include "Common\XUI\XUI_Scene_Trading.h" +#else +#include "Common\UI\UI.h" +#endif +#ifdef __PS3__ +#include "PS3/Network/SonyVoiceChat.h" +#endif +#include "DLCTexturePack.h" + +#ifdef _DURANGO +#include "..\Minecraft.World\DurangoStats.h" +#include "..\Minecraft.World\GenericStats.h" +#endif + +ClientConnection::ClientConnection(Minecraft *minecraft, const wstring& ip, int port) +{ + // 4J Stu - No longer used as we use the socket version below. + assert(FALSE); +#if 0 + // 4J - added initiliasers + random = new Random(); + done = false; + level = false; + started = false; + + this->minecraft = minecraft; + + Socket *socket; + if( gNetworkManager.IsHost() ) + { + socket = new Socket(); // 4J - Local connection + } + else + { + socket = new Socket(ip); // 4J - Connection over xrnm - hardcoded IP at present + } + createdOk = socket->createdOk; + if( createdOk ) + { + connection = new Connection(socket, L"Client", this); + } + else + { + connection = NULL; + delete socket; + } +#endif +} + +ClientConnection::ClientConnection(Minecraft *minecraft, Socket *socket, int iUserIndex /*= -1*/) +{ + // 4J - added initiliasers + random = new Random(); + done = false; + level = NULL; + started = false; + savedDataStorage = new SavedDataStorage(NULL); + maxPlayers = 20; + + this->minecraft = minecraft; + + if( iUserIndex < 0 ) + { + m_userIndex = ProfileManager.GetPrimaryPad(); + } + else + { + m_userIndex = iUserIndex; + } + + if( socket == NULL ) + { + socket = new Socket(); // 4J - Local connection + } + + createdOk = socket->createdOk; + if( createdOk ) + { + connection = new Connection(socket, L"Client", this); + } + else + { + connection = NULL; + // TODO 4J Stu - This will cause issues since the session player owns the socket + //delete socket; + } +} + +ClientConnection::~ClientConnection() +{ + delete connection; + delete random; + delete savedDataStorage; +} + +void ClientConnection::tick() +{ + if (!done) connection->tick(); + connection->flush(); +} + +INetworkPlayer *ClientConnection::getNetworkPlayer() +{ + if( connection != NULL && connection->getSocket() != NULL) return connection->getSocket()->getPlayer(); + else return NULL; +} + +void ClientConnection::handleLogin(shared_ptr packet) +{ + if (done) return; + + PlayerUID OnlineXuid; + ProfileManager.GetXUID(m_userIndex,&OnlineXuid,true); // online xuid + MOJANG_DATA *pMojangData = NULL; + + if(!g_NetworkManager.IsLocalGame()) + { + pMojangData=app.GetMojangDataForXuid(OnlineXuid); + } + + if(!g_NetworkManager.IsHost() ) + { + Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCLoginReceived * 100)/ (eCCConnected)); + } + + // 4J-PB - load the local player skin (from the global title user storage area) if there is one + // the primary player on the host machine won't have a qnet player from the socket + INetworkPlayer *networkPlayer = connection->getSocket()->getPlayer(); + int iUserID=-1; + + if( m_userIndex == ProfileManager.GetPrimaryPad() ) + { + iUserID=m_userIndex; + + TelemetryManager->SetMultiplayerInstanceId(packet->m_multiplayerInstanceId); + } + else + { + if(!networkPlayer->IsGuest() && networkPlayer->IsLocal()) + { + // find the pad number of this local player + for(int i=0;iwchSkin[0]!=0L) + { + wstring wstr=pMojangData->wchSkin; + // check the file is not already in + bRes=app.IsFileInMemoryTextures(wstr); + if(!bRes) + { +#ifdef _XBOX + C4JStorage::ETMSStatus eTMSStatus; + eTMSStatus=StorageManager.ReadTMSFile(iUserID,C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic,pMojangData->wchSkin,&pBuffer, &dwSize); + + bRes=(eTMSStatus==C4JStorage::ETMSStatus_Idle); +#endif + } + + if(bRes) + { + app.AddMemoryTextureFile(wstr,pBuffer,dwSize); + } + } + + // a cloak? + if(pMojangData->wchCape[0]!=0L) + { + wstring wstr=pMojangData->wchCape; + // check the file is not already in + bRes=app.IsFileInMemoryTextures(wstr); + if(!bRes) + { +#ifdef _XBOX + C4JStorage::ETMSStatus eTMSStatus; + eTMSStatus=StorageManager.ReadTMSFile(iUserID,C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic,pMojangData->wchCape,&pBuffer, &dwSize); + bRes=(eTMSStatus==C4JStorage::ETMSStatus_Idle); +#endif + } + + if(bRes) + { + app.AddMemoryTextureFile(wstr,pBuffer,dwSize); + } + } + } + + // If we're online, read the banned game list + app.ReadBannedList(iUserID); + // mark the level as not checked against banned levels - it'll be checked once the level starts + app.SetBanListCheck(iUserID,false); + } + + if( m_userIndex == ProfileManager.GetPrimaryPad() ) + { + if( app.GetTutorialMode() ) + { + minecraft->gameMode = new FullTutorialMode(ProfileManager.GetPrimaryPad(), minecraft, this); + } + // check if we're in the trial version + else if(ProfileManager.IsFullVersion()==false) + { + minecraft->gameMode = new TrialMode(ProfileManager.GetPrimaryPad(), minecraft, this); + } + else + { + MemSect(13); + minecraft->gameMode = new ConsoleGameMode(ProfileManager.GetPrimaryPad(), minecraft, this); + MemSect(0); + } + + + Level *dimensionLevel = minecraft->getLevel( packet->dimension ); + if( dimensionLevel == NULL ) + { + level = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, false, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty); + + // 4J Stu - We want to share the SavedDataStorage between levels + int otherDimensionId = packet->dimension == 0 ? -1 : 0; + Level *activeLevel = minecraft->getLevel(otherDimensionId); + if( activeLevel != NULL ) + { + // Don't need to delete it here as it belongs to a client connection while will delete it when it's done + //if( level->savedDataStorage != NULL ) delete level->savedDataStorage; + level->savedDataStorage = activeLevel->savedDataStorage; + } + + app.DebugPrintf("ClientConnection - DIFFICULTY --- %d\n",packet->difficulty); + level->difficulty = packet->difficulty; // 4J Added + level->isClientSide = true; + minecraft->setLevel(level); + } + + minecraft->player->setPlayerIndex( packet->m_playerIndex ); + minecraft->player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) ); + minecraft->player->setCustomCape( app.GetPlayerCapeId(m_userIndex) ); + + + minecraft->createPrimaryLocalPlayer(ProfileManager.GetPrimaryPad()); + + minecraft->player->dimension = packet->dimension; + //minecraft->setScreen(new ReceivingLevelScreen(this)); + minecraft->player->entityId = packet->clientVersion; + + BYTE networkSmallId = getSocket()->getSmallId(); + app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges); + minecraft->player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges); + + // Assume all privileges are on, so that the first message we see only indicates things that have been turned off + unsigned int startingPrivileges = 0; + Player::enableAllPlayerPrivileges(startingPrivileges,true); + + if(networkPlayer->IsHost()) + { + Player::setPlayerGamePrivilege(startingPrivileges, Player::ePlayerGamePrivilege_HOST,1); + } + + displayPrivilegeChanges(minecraft->player,startingPrivileges); + + // update the debugoptions + app.SetGameSettingsDebugMask(ProfileManager.GetPrimaryPad(),app.GetGameSettingsDebugMask(-1,true)); + } + else + { + // 4J-PB - this isn't the level we want + //level = (MultiPlayerLevel *)minecraft->level; + level = (MultiPlayerLevel *)minecraft->getLevel( packet->dimension ); + shared_ptr player; + + if(level==NULL) + { + int otherDimensionId = packet->dimension == 0 ? -1 : 0; + MultiPlayerLevel *activeLevel = minecraft->getLevel(otherDimensionId); + + if(activeLevel == NULL) + { + otherDimensionId = packet->dimension == 0 ? 1 : (packet->dimension == -1 ? 1 : -1); + activeLevel = minecraft->getLevel(otherDimensionId); + } + + MultiPlayerLevel *dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->seed, GameType::byId(packet->gameType), false, false, packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty); + + dimensionLevel->savedDataStorage = activeLevel->savedDataStorage; + + dimensionLevel->difficulty = packet->difficulty; // 4J Added + dimensionLevel->isClientSide = true; + level = dimensionLevel; + // 4J Stu - At time of writing ProfileManager.GetGamertag() does not always return the correct name, + // if sign-ins are turned off while the player signed in. Using the qnetPlayer instead. + // need to have a level before create extra local player + MultiPlayerLevel *levelpassedin=(MultiPlayerLevel *)level; + player = minecraft->createExtraLocalPlayer(m_userIndex, networkPlayer->GetOnlineName(), m_userIndex, packet->dimension, this,levelpassedin); + + // need to have a player before the setlevel + shared_ptr lastPlayer = minecraft->player; + minecraft->player = minecraft->localplayers[m_userIndex]; + minecraft->setLevel(level); + minecraft->player = lastPlayer; + } + else + { + player = minecraft->createExtraLocalPlayer(m_userIndex, networkPlayer->GetOnlineName(), m_userIndex, packet->dimension, this); + } + + + //level->addClientConnection( this ); + player->dimension = packet->dimension; + player->entityId = packet->clientVersion; + + player->setPlayerIndex( packet->m_playerIndex ); + player->setCustomSkin( app.GetPlayerSkinId(m_userIndex) ); + player->setCustomCape( app.GetPlayerCapeId(m_userIndex) ); + + + BYTE networkSmallId = getSocket()->getSmallId(); + app.UpdatePlayerInfo(networkSmallId, packet->m_playerIndex, packet->m_uiGamePrivileges); + player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges); + + // Assume all privileges are on, so that the first message we see only indicates things that have been turned off + unsigned int startingPrivileges = 0; + Player::enableAllPlayerPrivileges(startingPrivileges,true); + + displayPrivilegeChanges(minecraft->localplayers[m_userIndex],startingPrivileges); + } + + maxPlayers = packet->maxPlayers; + + // need to have a player before the setLocalCreativeMode + shared_ptr lastPlayer = minecraft->player; + minecraft->player = minecraft->localplayers[m_userIndex]; + ((MultiPlayerGameMode *)minecraft->localgameModes[m_userIndex])->setLocalMode(GameType::byId(packet->gameType)); + minecraft->player = lastPlayer; + + // make sure the UI offsets for this player are set correctly + if(iUserID!=-1) + { + ui.UpdateSelectedItemPos(iUserID); + } + + TelemetryManager->RecordLevelStart(m_userIndex, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->getLevel(packet->dimension)->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount()); +} + +void ClientConnection::handleAddEntity(shared_ptr packet) +{ + double x = packet->x / 32.0; + double y = packet->y / 32.0; + double z = packet->z / 32.0; + shared_ptr e; + boolean setRot = true; + + // 4J-PB - replacing this massive if nest with switch + switch(packet->type) + { + case AddEntityPacket::MINECART_RIDEABLE: + e = shared_ptr( new Minecart(level, x, y, z, Minecart::RIDEABLE) ); + break; + case AddEntityPacket::MINECART_CHEST: + e = shared_ptr( new Minecart(level, x, y, z, Minecart::CHEST) ); + break; + + case AddEntityPacket::MINECART_FURNACE: + e = shared_ptr( new Minecart(level, x, y, z, Minecart::FURNACE) ); + break; + + case AddEntityPacket::FISH_HOOK: + { + // 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing + shared_ptr owner = getEntity(packet->data); + + // 4J - check all local players to find match + if( owner == NULL ) + { + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + if( minecraft->localplayers[i] ) + { + if( minecraft->localplayers[i]->entityId == packet->data ) + { + + owner = minecraft->localplayers[i]; + break; + } + } + } + } + shared_ptr player = dynamic_pointer_cast(owner); + if (player != NULL) + { + shared_ptr hook = shared_ptr( new FishingHook(level, x, y, z, player) ); + e = hook; + // 4J Stu - Move the player->fishing out of the ctor as we cannot reference 'this' + player->fishing = hook; + } + packet->data = 0; + } + break; + case AddEntityPacket::ARROW: + e = shared_ptr( new Arrow(level, x, y, z) ); + break; + case AddEntityPacket::SNOWBALL: + e = shared_ptr( new Snowball(level, x, y, z) ); + break; + case AddEntityPacket::ITEM_FRAME: + { + int ix=(int) x; + int iy=(int) y; + int iz = (int) z; + app.DebugPrintf("ClientConnection ITEM_FRAME xyz %d,%d,%d\n",ix,iy,iz); + } + e = shared_ptr(new ItemFrame(level, (int) x, (int) y, (int) z, packet->data)); + packet->data = 0; + setRot = false; + break; + case AddEntityPacket::THROWN_ENDERPEARL: + e = shared_ptr( new ThrownEnderpearl(level, x, y, z) ); + break; + case AddEntityPacket::EYEOFENDERSIGNAL: + e = shared_ptr( new EyeOfEnderSignal(level, x, y, z) ); + break; + case AddEntityPacket::FIREBALL: + e = shared_ptr( new Fireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); + packet->data = 0; + break; + case AddEntityPacket::SMALL_FIREBALL: + e = shared_ptr( new SmallFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); + packet->data = 0; + break; + case AddEntityPacket::DRAGON_FIRE_BALL: + e = shared_ptr( new DragonFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); + packet->data = 0; + break; + case AddEntityPacket::EGG: + e = shared_ptr( new ThrownEgg(level, x, y, z) ); + break; + case AddEntityPacket::THROWN_POTION: + e = shared_ptr( new ThrownPotion(level, x, y, z, packet->data) ); + packet->data = 0; + break; + case AddEntityPacket::THROWN_EXPBOTTLE: + e = shared_ptr( new ThrownExpBottle(level, x, y, z) ); + packet->data = 0; + break; + case AddEntityPacket::BOAT: + e = shared_ptr( new Boat(level, x, y, z) ); + break; + case AddEntityPacket::PRIMED_TNT: + e = shared_ptr( new PrimedTnt(level, x, y, z) ); + break; + case AddEntityPacket::ENDER_CRYSTAL: + e = shared_ptr( new EnderCrystal(level, x, y, z) ); + break; + case AddEntityPacket::ITEM: + e = shared_ptr( new ItemEntity(level, x, y, z) ); + break; + case AddEntityPacket::FALLING: + e = shared_ptr( new FallingTile(level, x, y, z, packet->data & 0xFFFF, packet->data >> 16) ); + packet->data = 0; + break; + + + + } + /* if (packet->type == AddEntityPacket::MINECART_RIDEABLE) e = shared_ptr( new Minecart(level, x, y, z, Minecart::RIDEABLE) ); + if (packet->type == AddEntityPacket::MINECART_CHEST) e = shared_ptr( new Minecart(level, x, y, z, Minecart::CHEST) ); + if (packet->type == AddEntityPacket::MINECART_FURNACE) e = shared_ptr( new Minecart(level, x, y, z, Minecart::FURNACE) ); + if (packet->type == AddEntityPacket::FISH_HOOK) + { + // 4J Stu - Brought forward from 1.4 to be able to drop XP from fishing + shared_ptr owner = getEntity(packet->data); + + // 4J - check all local players to find match + if( owner == NULL ) + { + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + if( minecraft->localplayers[i] ) + { + if( minecraft->localplayers[i]->entityId == packet->data ) + { + + owner = minecraft->localplayers[i]; + break; + } + } + } + } + shared_ptr player = dynamic_pointer_cast(owner); + if (player != NULL) + { + shared_ptr hook = shared_ptr( new FishingHook(level, x, y, z, player) ); + e = hook; + // 4J Stu - Move the player->fishing out of the ctor as we cannot reference 'this' + player->fishing = hook; + } + packet->data = 0; + } + + if (packet->type == AddEntityPacket::ARROW) e = shared_ptr( new Arrow(level, x, y, z) ); + if (packet->type == AddEntityPacket::SNOWBALL) e = shared_ptr( new Snowball(level, x, y, z) ); + if (packet->type == AddEntityPacket::THROWN_ENDERPEARL) e = shared_ptr( new ThrownEnderpearl(level, x, y, z) ); + if (packet->type == AddEntityPacket::EYEOFENDERSIGNAL) e = shared_ptr( new EyeOfEnderSignal(level, x, y, z) ); + if (packet->type == AddEntityPacket::FIREBALL) + { + e = shared_ptr( new Fireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); + packet->data = 0; + } + if (packet->type == AddEntityPacket::SMALL_FIREBALL) + { + e = shared_ptr( new SmallFireball(level, x, y, z, packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0) ); + packet->data = 0; + } + if (packet->type == AddEntityPacket::EGG) e = shared_ptr( new ThrownEgg(level, x, y, z) ); + if (packet->type == AddEntityPacket::THROWN_POTION) + { + e = shared_ptr( new ThrownPotion(level, x, y, z, packet->data) ); + packet->data = 0; + } + if (packet->type == AddEntityPacket::THROWN_EXPBOTTLE) + { + e = shared_ptr( new ThrownExpBottle(level, x, y, z) ); + packet->data = 0; + } + if (packet->type == AddEntityPacket::BOAT) e = shared_ptr( new Boat(level, x, y, z) ); + if (packet->type == AddEntityPacket::PRIMED_TNT) e = shared_ptr( new PrimedTnt(level, x, y, z) ); + if (packet->type == AddEntityPacket::ENDER_CRYSTAL) e = shared_ptr( new EnderCrystal(level, x, y, z) ); + if (packet->type == AddEntityPacket::FALLING_SAND) e = shared_ptr( new FallingTile(level, x, y, z, Tile::sand->id) ); + if (packet->type == AddEntityPacket::FALLING_GRAVEL) e = shared_ptr( new FallingTile(level, x, y, z, Tile::gravel->id) ); + if (packet->type == AddEntityPacket::FALLING_EGG) e = shared_ptr( new FallingTile(level, x, y, z, Tile::dragonEgg_Id) ); + + */ + + if (e != NULL) + { + e->xp = packet->x; + e->yp = packet->y; + e->zp = packet->z; + + float yRot = packet->yRot * 360 / 256.0f; + float xRot = packet->xRot * 360 / 256.0f; + e->yRotp = packet->yRot; + e->xRotp = packet->xRot; + + if (setRot) + { + e->yRot = 0.0f; + e->xRot = 0.0f; + } + + vector > *subEntities = e->getSubEntities(); + if (subEntities != NULL) + { + int offs = packet->id - e->entityId; + //for (int i = 0; i < subEntities.length; i++) + for(AUTO_VAR(it, subEntities->begin()); it != subEntities->end(); ++it) + { + (*it)->entityId += offs; + //subEntities[i].entityId += offs; + //System.out.println(subEntities[i].entityId); + } + } + + // Note - not doing this move for frame, as the ctor for these objects does some adjustments on the position based on direction to move the object out slightly from what it is attached to, and this just overwrites it + if( packet->type != AddEntityPacket::ITEM_FRAME ) + { + e->absMoveTo(x,y,z,yRot,xRot); + } + e->entityId = packet->id; + level->putEntity(packet->id, e); + + if (packet->data > -1) // 4J - changed "no data" value to be -1, we can have a valid entity id of 0 + { + + if (packet->type == AddEntityPacket::ARROW) + { + shared_ptr owner = getEntity(packet->data); + + // 4J - check all local players to find match + if( owner == NULL ) + { + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + if( minecraft->localplayers[i] ) + { + if( minecraft->localplayers[i]->entityId == packet->data ) + { + owner = minecraft->localplayers[i]; + break; + } + } + } + } + + if (dynamic_pointer_cast(owner) != NULL) + { + dynamic_pointer_cast(e)->owner = dynamic_pointer_cast(owner); + } + } + + e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0); + } + } + +} + +void ClientConnection::handleAddExperienceOrb(shared_ptr packet) +{ + shared_ptr e = shared_ptr( new ExperienceOrb(level, packet->x / 32.0, packet->y / 32.0, packet->z / 32.0, packet->value) ); + e->xp = packet->x; + e->yp = packet->y; + e->zp = packet->z; + e->yRot = 0; + e->xRot = 0; + e->entityId = packet->id; + level->putEntity(packet->id, e); +} + +void ClientConnection::handleAddGlobalEntity(shared_ptr packet) +{ + double x = packet->x / 32.0; + double y = packet->y / 32.0; + double z = packet->z / 32.0; + shared_ptr e;// = nullptr; + if (packet->type == AddGlobalEntityPacket::LIGHTNING) e = shared_ptr( new LightningBolt(level, x, y, z) ); + if (e != NULL) + { + e->xp = packet->x; + e->yp = packet->y; + e->zp = packet->z; + e->yRot = 0; + e->xRot = 0; + e->entityId = packet->id; + level->addGlobalEntity(e); + } +} + +void ClientConnection::handleAddPainting(shared_ptr packet) +{ + shared_ptr painting = shared_ptr( new Painting(level, packet->x, packet->y, packet->z, packet->dir, packet->motive) ); + level->putEntity(packet->id, painting); +} + +void ClientConnection::handleSetEntityMotion(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + e->lerpMotion(packet->xa / 8000.0, packet->ya / 8000.0, packet->za / 8000.0); +} + +void ClientConnection::handleSetEntityData(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e != NULL && packet->getUnpackedData() != NULL) + { + e->getEntityData()->assignValues(packet->getUnpackedData()); + } +} + +void ClientConnection::handleAddPlayer(shared_ptr packet) +{ + // Some remote players could actually be local players that are already added + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + // need to use the XUID here + PlayerUID playerXUIDOnline = INVALID_XUID, playerXUIDOffline = INVALID_XUID; + ProfileManager.GetXUID(idx,&playerXUIDOnline,true); + ProfileManager.GetXUID(idx,&playerXUIDOffline,false); + if( (playerXUIDOnline != INVALID_XUID && ProfileManager.AreXUIDSEqual(playerXUIDOnline,packet->xuid) ) || + (playerXUIDOffline != INVALID_XUID && ProfileManager.AreXUIDSEqual(playerXUIDOffline,packet->xuid) ) ) + { + app.DebugPrintf("AddPlayerPacket received with XUID of local player\n"); + return; + } + } + + double x = packet->x / 32.0; + double y = packet->y / 32.0; + double z = packet->z / 32.0; + float yRot = packet->yRot * 360 / 256.0f; + float xRot = packet->xRot * 360 / 256.0f; + shared_ptr player = shared_ptr( new RemotePlayer(minecraft->level, packet->name) ); + player->xo = player->xOld = player->xp = packet->x; + player->yo = player->yOld = player->yp = packet->y; + player->zo = player->zOld = player->zp = packet->z; + player->xRotp = packet->xRot; + player->yRotp = packet->yRot; + player->yHeadRot = packet->yHeadRot * 360 / 256.0f; + player->setXuid(packet->xuid); + +#ifdef _DURANGO + // On Durango request player display name from network manager + INetworkPlayer *networkPlayer = g_NetworkManager.GetPlayerByXuid(player->getXuid()); + if (networkPlayer != NULL) player->displayName = networkPlayer->GetDisplayName(); +#else + // On all other platforms display name is just gamertag so don't check with the network manager + player->displayName = player->name; +#endif + + // printf("\t\t\t\t%d: Add player\n",packet->id,packet->yRot); + + int item = packet->carriedItem; + if (item == 0) + { + player->inventory->items[player->inventory->selected] = shared_ptr(); // NULL; + } + else + { + player->inventory->items[player->inventory->selected] = shared_ptr( new ItemInstance(item, 1, 0) ); + } + player->absMoveTo(x, y, z, yRot, xRot); + + player->setPlayerIndex( packet->m_playerIndex ); + player->setCustomSkin( packet->m_skinId ); + player->setCustomCape( packet->m_capeId ); + player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_uiGamePrivileges); + + if(!player->customTextureUrl.empty() && player->customTextureUrl.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl)) + { + if( minecraft->addPendingClientTextureRequest(player->customTextureUrl) ) + { + app.DebugPrintf("Client sending TextureAndGeometryPacket to get custom skin %ls for player %ls\n",player->customTextureUrl.c_str(), player->name.c_str()); + + send(shared_ptr( new TextureAndGeometryPacket(player->customTextureUrl,NULL,0) ) ); + } + } + else if(!player->customTextureUrl.empty() && app.IsFileInMemoryTextures(player->customTextureUrl)) + { + // Update the ref count on the memory texture data + app.AddMemoryTextureFile(player->customTextureUrl,NULL,0); + } + + app.DebugPrintf("Custom skin for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl.c_str()); + + if(!player->customTextureUrl2.empty() && player->customTextureUrl2.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(player->customTextureUrl2)) + { + if( minecraft->addPendingClientTextureRequest(player->customTextureUrl2) ) + { + app.DebugPrintf("Client sending texture packet to get custom cape %ls for player %ls\n",player->customTextureUrl2.c_str(), player->name.c_str()); + send(shared_ptr( new TexturePacket(player->customTextureUrl2,NULL,0) ) ); + } + } + else if(!player->customTextureUrl2.empty() && app.IsFileInMemoryTextures(player->customTextureUrl2)) + { + // Update the ref count on the memory texture data + app.AddMemoryTextureFile(player->customTextureUrl2,NULL,0); + } + + app.DebugPrintf("Custom cape for player %ls is %ls\n",player->name.c_str(),player->customTextureUrl2.c_str()); + + level->putEntity(packet->id, player); + + vector > *unpackedData = packet->getUnpackedData(); + if (unpackedData != NULL) + { + player->getEntityData()->assignValues(unpackedData); + } + +} + +void ClientConnection::handleTeleportEntity(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + e->xp = packet->x; + e->yp = packet->y; + e->zp = packet->z; + double x = e->xp / 32.0; + double y = e->yp / 32.0 + 1 / 64.0f; + double z = e->zp / 32.0; + // 4J - make sure xRot stays within -90 -> 90 range + int ixRot = packet->xRot; + if( ixRot >= 128 ) ixRot -= 256; + float yRot = packet->yRot * 360 / 256.0f; + float xRot = ixRot * 360 / 256.0f; + e->yRotp = packet->yRot; + e->xRotp = ixRot; + +// printf("\t\t\t\t%d: Teleport to %d (lerp to %f)\n",packet->id,packet->yRot,yRot); + e->lerpTo(x, y, z, yRot, xRot, 3); +} + +void ClientConnection::handleMoveEntity(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + e->xp += packet->xa; + e->yp += packet->ya; + e->zp += packet->za; + double x = e->xp / 32.0; + // 4J - The original code did not add the 1/64.0f like the teleport above did, which caused minecarts to fall through the ground + double y = e->yp / 32.0 + 1 / 64.0f; + double z = e->zp / 32.0; + // 4J - have changed rotation to be relative here too + e->yRotp += packet->yRot; + e->xRotp += packet->xRot; + float yRot = ( e->yRotp * 360 ) / 256.0f; + float xRot = ( e->xRotp * 360 ) / 256.0f; +// float yRot = packet->hasRot ? packet->yRot * 360 / 256.0f : e->yRot; +// float xRot = packet->hasRot ? packet->xRot * 360 / 256.0f : e->xRot; + e->lerpTo(x, y, z, yRot, xRot, 3); +} + +void ClientConnection::handleRotateMob(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + float yHeadRot = packet->yHeadRot * 360 / 256.f; + e->setYHeadRot(yHeadRot); +} + +void ClientConnection::handleMoveEntitySmall(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + e->xp += packet->xa; + e->yp += packet->ya; + e->zp += packet->za; + double x = e->xp / 32.0; + // 4J - The original code did not add the 1/64.0f like the teleport above did, which caused minecarts to fall through the ground + double y = e->yp / 32.0 + 1 / 64.0f; + double z = e->zp / 32.0; + // 4J - have changed rotation to be relative here too + e->yRotp += packet->yRot; + e->xRotp += packet->xRot; + float yRot = ( e->yRotp * 360 ) / 256.0f; + float xRot = ( e->xRotp * 360 ) / 256.0f; +// float yRot = packet->hasRot ? packet->yRot * 360 / 256.0f : e->yRot; +// float xRot = packet->hasRot ? packet->xRot * 360 / 256.0f : e->xRot; + e->lerpTo(x, y, z, yRot, xRot, 3); +} + +void ClientConnection::handleRemoveEntity(shared_ptr packet) +{ + for (int i = 0; i < packet->ids.length; i++) + { + level->removeEntity(packet->ids[i]); + } +} + +void ClientConnection::handleMovePlayer(shared_ptr packet) +{ + shared_ptr player = minecraft->localplayers[m_userIndex]; //minecraft->player; + + double x = player->x; + double y = player->y; + double z = player->z; + float yRot = player->yRot; + float xRot = player->xRot; + + if (packet->hasPos) + { + x = packet->x; + y = packet->y; + z = packet->z; + } + if (packet->hasRot) + { + yRot = packet->yRot; + xRot = packet->xRot; + } + + player->ySlideOffset = 0; + player->xd = player->yd = player->zd = 0; + player->absMoveTo(x, y, z, yRot, xRot); + packet->x = player->x; + packet->y = player->bb->y0; + packet->z = player->z; + packet->yView = player->y; + connection->send(packet); + if (!started) + { + + if(!g_NetworkManager.IsHost() ) + { + Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCConnected * 100)/ (eCCConnected)); + } + player->xo = player->x; + player->yo = player->y; + player->zo = player->z; + // 4J - added setting xOld/yOld/zOld here too, as otherwise at the start of the game we interpolate the player position from the origin to wherever its first position really is + player->xOld = player->x; + player->yOld = player->y; + player->zOld = player->z; + + started = true; + minecraft->setScreen(NULL); + + // Fix for #105852 - TU12: Content: Gameplay: Local splitscreen Players are spawned at incorrect places after re-joining previously saved and loaded "Mass Effect World". + // Move this check from Minecraft::createExtraLocalPlayer + // 4J-PB - can't call this when this function is called from the qnet thread (GetGameStarted will be false) + if(app.GetGameStarted()) + { + ui.CloseUIScenes(m_userIndex); + } + } + +} + +// 4J Added +void ClientConnection::handleChunkVisibilityArea(shared_ptr packet) +{ + for(int z = packet->m_minZ; z <= packet->m_maxZ; ++z) + for(int x = packet->m_minX; x <= packet->m_maxX; ++x) + level->setChunkVisible(x, z, true); +} + +void ClientConnection::handleChunkVisibility(shared_ptr packet) +{ + level->setChunkVisible(packet->x, packet->z, packet->visible); +} + +void ClientConnection::handleChunkTilesUpdate(shared_ptr packet) +{ + // 4J - changed to encode level in packet + MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; + if( dimensionLevel ) + { + PIXBeginNamedEvent(0,"Handle chunk tiles update"); + LevelChunk *lc = dimensionLevel->getChunk(packet->xc, packet->zc); + int xo = packet->xc * 16; + int zo = packet->zc * 16; + // 4J Stu - Unshare before we make any changes incase the server is already another step ahead of us + // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. + // This is quite expensive to do, so only consider unsharing if this tile setting is going to actually + // change something + bool forcedUnshare = false; + for (int i = 0; i < packet->count; i++) + { + int pos = packet->positions[i]; + int tile = packet->blocks[i] & 0xff; + int data = packet->data[i]; + + + int x = (pos >> 12) & 15; + int z = (pos >> 8) & 15; + int y = ((pos) & 255); + + // If this is going to actually change a tile, we'll need to unshare + int prevTile = lc->getTile(x, y, z); + if( ( tile != prevTile && !forcedUnshare ) ) + { + PIXBeginNamedEvent(0,"Chunk data unsharing\n"); + dimensionLevel->unshareChunkAt(xo,zo); + PIXEndNamedEvent(); + forcedUnshare = true; + } + + // 4J - Changes now that lighting is done at the client side of things... + // Note - the java version now calls the doSetTileAndData method from the level here rather than the levelchunk, which ultimately ends up + // calling checkLight for the altered tile. For us this doesn't always work as when sharing tile data between a local server & client, the + // tile might not be considered to be being changed on the client as the server already has changed the shared data, and so the checkLight + // doesn't happen. Hence doing an explicit checkLight here instead. + lc->setTileAndData(x, y, z, tile, data); + dimensionLevel->checkLight(x + xo, y, z + zo); + + dimensionLevel->clearResetRegion(x + xo, y, z + zo, x + xo, y, z + zo); + + // Don't bother setting this to dirty if it isn't going to visually change - we get a lot of + // water changing from static to dynamic for instance + if(!( ( ( prevTile == Tile::water_Id ) && ( tile == Tile::calmWater_Id ) ) || + ( ( prevTile == Tile::calmWater_Id ) && ( tile == Tile::water_Id ) ) || + ( ( prevTile == Tile::lava_Id ) && ( tile == Tile::calmLava_Id ) ) || + ( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::calmLava_Id ) ) || + ( ( prevTile == Tile::calmLava_Id ) && ( tile == Tile::lava_Id ) ) ) ) + { + dimensionLevel->setTilesDirty(x + xo, y, z + zo, x + xo, y, z + zo); + } + + // 4J - remove any tite entities in this region which are associated with a tile that is now no longer a tile entity. Without doing this we end up with stray + // tile entities kicking round, which leads to a bug where chests can't be properly placed again in a location after (say) a chest being removed by TNT + dimensionLevel->removeUnusedTileEntitiesInRegion(xo + x, y, zo + z, xo + x+1, y+1, zo + z+1); + } + PIXBeginNamedEvent(0,"Chunk data sharing\n"); + dimensionLevel->shareChunkAt(xo,zo); // 4J - added - only shares if chunks are same on server & client + PIXEndNamedEvent(); + + PIXEndNamedEvent(); + } +} + +void ClientConnection::handleBlockRegionUpdate(shared_ptr packet) +{ + // 4J - changed to encode level in packet + MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; + if( dimensionLevel ) + { + PIXBeginNamedEvent(0,"Handle block region update"); + + int y1 = packet->y + packet->ys; + if(packet->bIsFullChunk) + { + y1 = Level::maxBuildHeight; + if(packet->buffer.length > 0) LevelChunk::reorderBlocksAndDataToXZY(packet->y, packet->xs, packet->ys, packet->zs, &packet->buffer); + } + dimensionLevel->clearResetRegion(packet->x, packet->y, packet->z, packet->x + packet->xs - 1, y1 - 1, packet->z + packet->zs - 1); + + // Only full chunks send lighting information now - added flag to end of this call + dimensionLevel->setBlocksAndData(packet->x, packet->y, packet->z, packet->xs, packet->ys, packet->zs, packet->buffer, packet->bIsFullChunk); + +// OutputDebugString("END BRU\n"); + + // 4J - remove any tite entities in this region which are associated with a tile that is now no longer a tile entity. Without doing this we end up with stray + // tile entities kicking round, which leads to a bug where chests can't be properly placed again in a location after (say) a chest being removed by TNT + dimensionLevel->removeUnusedTileEntitiesInRegion(packet->x, packet->y, packet->z, packet->x + packet->xs, y1, packet->z + packet->zs ); + + // If this is a full packet for a chunk, make sure that the cache now considers that it has data for this chunk - this is used to determine whether to bother + // rendering mobs or not, so we don't have them in crazy positions before the data is there + if( packet->bIsFullChunk ) + { + dimensionLevel->dataReceivedForChunk( packet->x >> 4, packet->z >> 4 ); + } + PIXEndNamedEvent(); + } +} + +void ClientConnection::handleTileUpdate(shared_ptr packet) +{ + // 4J added - using a block of 255 to signify that this is a packet for destroying a tile, where we need to inform the level renderer that we are about to do so. + // This is used in creative mode as the point where a tile is first destroyed at the client end of things. Packets formed like this are potentially sent from + // ServerPlayerGameMode::destroyBlock + bool destroyTilePacket = false; + if( packet->block == 255 ) + { + packet->block = 0; + destroyTilePacket = true; + } + // 4J - changed to encode level in packet + MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->levels[packet->levelIdx]; + if( dimensionLevel ) + { + PIXBeginNamedEvent(0,"Handle tile update"); + + if( g_NetworkManager.IsHost() ) + { + // 4J Stu - Unshare before we make any changes incase the server is already another step ahead of us + // Fix for #7904 - Gameplay: Players can dupe torches by throwing them repeatedly into water. + // This is quite expensive to do, so only consider unsharing if this tile setting is going to actually + // change something + int prevTile = dimensionLevel->getTile(packet->x, packet->y, packet->z); + int prevData = dimensionLevel->getData(packet->x, packet->y, packet->z); + if( packet->block != prevTile || packet->data != prevData ) + { + PIXBeginNamedEvent(0,"Chunk data unsharing\n"); + dimensionLevel->unshareChunkAt(packet->x,packet->z); + PIXEndNamedEvent(); + } + } + + // 4J - In creative mode, we don't update the tile locally then get it confirmed by the server - the first point that we know we are about to destroy a tile is here. Let + // the rendering side of thing know so we can synchronise collision with async render data upates. + if( destroyTilePacket ) + { + minecraft->levelRenderer->destroyedTileManager->destroyingTileAt(dimensionLevel, packet->x, packet->y, packet->z); + } + + PIXBeginNamedEvent(0,"Setting data\n"); + bool tileWasSet = dimensionLevel->doSetTileAndData(packet->x, packet->y, packet->z, packet->block, packet->data); + + PIXEndNamedEvent(); + + // 4J - remove any tite entities in this region which are associated with a tile that is now no longer a tile entity. Without doing this we end up with stray + // tile entities kicking round, which leads to a bug where chests can't be properly placed again in a location after (say) a chest being removed by TNT + dimensionLevel->removeUnusedTileEntitiesInRegion(packet->x, packet->y, packet->z, packet->x+1, packet->y+1, packet->z+1 ); + + PIXBeginNamedEvent(0,"Sharing data\n"); + dimensionLevel->shareChunkAt(packet->x,packet->z); // 4J - added - only shares if chunks are same on server & client + PIXEndNamedEvent(); + + PIXEndNamedEvent(); + } +} + +void ClientConnection::handleDisconnect(shared_ptr packet) +{ + connection->close(DisconnectPacket::eDisconnect_Kicked); + done = true; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->connectionDisconnected( m_userIndex , packet->reason ); + app.SetDisconnectReason( packet->reason ); + + app.SetAction(m_userIndex,eAppAction_ExitWorld,(void *)TRUE); + //minecraft->setLevel(NULL); + //minecraft->setScreen(new DisconnectedScreen(L"disconnect.disconnected", L"disconnect.genericReason", &packet->reason)); + +} + +void ClientConnection::onDisconnect(DisconnectPacket::eDisconnectReason reason, void *reasonObjects) +{ + if (done) return; + done = true; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->connectionDisconnected( m_userIndex , reason ); + + // 4J Stu - TU-1 hotfix + // Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost + // In the (now unlikely) event that the host connections times out, allow the player to save their game + if(g_NetworkManager.IsHost() && + (reason == DisconnectPacket::eDisconnect_TimeOut || reason == DisconnectPacket::eDisconnect_Overflow) && + m_userIndex == ProfileManager.GetPrimaryPad() && + !MinecraftServer::saveOnExitAnswered() ) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_EXITING_GAME, IDS_GENERIC_ERROR, uiIDA, 1, ProfileManager.GetPrimaryPad(),&ClientConnection::HostDisconnectReturned,NULL, app.GetStringTable()); + } + else + { + app.SetAction(m_userIndex,eAppAction_ExitWorld,(void *)TRUE); + } + + //minecraft->setLevel(NULL); + //minecraft->setScreen(new DisconnectedScreen(L"disconnect.lost", reason, reasonObjects)); +} + +void ClientConnection::sendAndDisconnect(shared_ptr packet) +{ + if (done) return; + connection->send(packet); + connection->sendAndQuit(); +} + +void ClientConnection::send(shared_ptr packet) +{ + if (done) return; + connection->send(packet); +} + +void ClientConnection::handleTakeItemEntity(shared_ptr packet) +{ + shared_ptr from = getEntity(packet->itemId); + shared_ptr to = dynamic_pointer_cast(getEntity(packet->playerId)); + + // 4J - the original game could assume that if getEntity didn't find the player, it must be the local player. We + // need to search all local players + bool isLocalPlayer = false; + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + if( minecraft->localplayers[i] ) + { + if( minecraft->localplayers[i]->entityId == packet->playerId ) + { + isLocalPlayer = true; + to = minecraft->localplayers[i]; + break; + } + } + } + + if (to == NULL) + { + // Don't know if this should ever really happen, but seems safest to try and remove the entity that has been collected even if we can't + // create a particle as we don't know what really collected it + level->removeEntity(packet->itemId); + return; + } + + if (from != NULL) + { + // If this is a local player, then we only want to do processing for it if this connection is associated with the player it is for. In + // particular, we don't want to remove the item entity until we are processing it for the right connection, or else we won't have a valid + // "from" reference if we've already removed the item for an earlier processed connection + if( isLocalPlayer ) + { + shared_ptr player = dynamic_pointer_cast(to); + + // 4J Stu - Fix for #10213 - UI: Local clients cannot progress through the tutorial normally. + // We only send this packet once if many local players can see the event, so make sure we update + // the tutorial for the player that actually picked up the item + int playerPad = player->GetXboxPad(); + + if( minecraft->localgameModes[playerPad] != NULL ) + { + // 4J-PB - add in the XP orb sound + if(from->GetType() == eTYPE_EXPERIENCEORB) + { + float fPitch=((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f; + app.DebugPrintf("XP Orb with pitch %f\n",fPitch); + level->playSound(from, eSoundType_RANDOM_ORB, 0.2f, fPitch); + } + else + { + level->playSound(from, eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); + } + + minecraft->particleEngine->add( shared_ptr( new TakeAnimationParticle(minecraft->level, from, to, -0.5f) ) ); + level->removeEntity(packet->itemId); + } + else + { + // Don't know if this should ever really happen, but seems safest to try and remove the entity that has been collected even if it + // somehow isn't an itementity + level->removeEntity(packet->itemId); + } + } + else + { + level->playSound(from, eSoundType_RANDOM_POP, 0.2f, ((random->nextFloat() - random->nextFloat()) * 0.7f + 1.0f) * 2.0f); + minecraft->particleEngine->add( shared_ptr( new TakeAnimationParticle(minecraft->level, from, to, -0.5f) ) ); + level->removeEntity(packet->itemId); + } + } + +} + +void ClientConnection::handleChat(shared_ptr packet) +{ + wstring message; + int iPos; + bool displayOnGui = true; + + wstring playerDisplayName = L""; + wstring sourceDisplayName = L""; + + // On platforms other than Xbox One this just sets display name to gamertag + if (packet->m_stringArgs.size() >= 1) playerDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[0]); + if (packet->m_stringArgs.size() >= 2) sourceDisplayName = GetDisplayNameByGamertag(packet->m_stringArgs[1]); + + switch(packet->m_messageType) + { + case ChatPacket::e_ChatBedOccupied: + message = app.GetString(IDS_TILE_BED_OCCUPIED); + break; + case ChatPacket::e_ChatBedNoSleep: + message = app.GetString(IDS_TILE_BED_NO_SLEEP); + break; + case ChatPacket::e_ChatBedNotValid: + message = app.GetString(IDS_TILE_BED_NOT_VALID); + break; + case ChatPacket::e_ChatBedNotSafe: + message = app.GetString(IDS_TILE_BED_NOTSAFE); + break; + case ChatPacket::e_ChatBedPlayerSleep: + message=app.GetString(IDS_TILE_BED_PLAYERSLEEP); + iPos=message.find(L"%s"); + message.replace(iPos,2,playerDisplayName); + break; + case ChatPacket::e_ChatBedMeSleep: + message=app.GetString(IDS_TILE_BED_MESLEEP); + break; + case ChatPacket::e_ChatPlayerJoinedGame: + message=app.GetString(IDS_PLAYER_JOINED); + iPos=message.find(L"%s"); + message.replace(iPos,2,playerDisplayName); + break; + case ChatPacket::e_ChatPlayerLeftGame: + message=app.GetString(IDS_PLAYER_LEFT); + iPos=message.find(L"%s"); + message.replace(iPos,2,playerDisplayName); + break; + case ChatPacket::e_ChatPlayerKickedFromGame: + message=app.GetString(IDS_PLAYER_KICKED); + iPos=message.find(L"%s"); + message.replace(iPos,2,playerDisplayName); + break; + case ChatPacket::e_ChatCannotPlaceLava: + displayOnGui = false; + app.SetGlobalXuiAction(eAppAction_DisplayLavaMessage); + break; + case ChatPacket::e_ChatDeathInFire: + message=app.GetString(IDS_DEATH_INFIRE); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathOnFire: + message=app.GetString(IDS_DEATH_ONFIRE); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathLava: + message=app.GetString(IDS_DEATH_LAVA); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathInWall: + message=app.GetString(IDS_DEATH_INWALL); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathDrown: + message=app.GetString(IDS_DEATH_DROWN); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathStarve: + message=app.GetString(IDS_DEATH_STARVE); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathCactus: + message=app.GetString(IDS_DEATH_CACTUS); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathFall: + message=app.GetString(IDS_DEATH_FALL); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathOutOfWorld: + message=app.GetString(IDS_DEATH_OUTOFWORLD); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathGeneric: + message=app.GetString(IDS_DEATH_GENERIC); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathExplosion: + message=app.GetString(IDS_DEATH_EXPLOSION); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathMagic: + message=app.GetString(IDS_DEATH_MAGIC); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathAnvil: + message=app.GetString(IDS_DEATH_FALLING_ANVIL); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathFallingBlock: + message=app.GetString(IDS_DEATH_FALLING_TILE); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathDragonBreath: + message=app.GetString(IDS_DEATH_DRAGON_BREATH); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatDeathMob: + message=app.GetString(IDS_DEATH_MOB); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + message = replaceAll(message,L"{*SOURCE*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + break; + case ChatPacket::e_ChatDeathPlayer: + message=app.GetString(IDS_DEATH_PLAYER); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + message = replaceAll(message,L"{*SOURCE*}",sourceDisplayName); + break; + case ChatPacket::e_ChatDeathArrow: + message=app.GetString(IDS_DEATH_ARROW); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) + { + message = replaceAll(message,L"{*SOURCE*}",sourceDisplayName); + } + else + { + message = replaceAll(message,L"{*SOURCE*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + } + break; + case ChatPacket::e_ChatDeathFireball: + message=app.GetString(IDS_DEATH_FIREBALL); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) + { + message = replaceAll(message,L"{*SOURCE*}",packet->m_stringArgs[1]); + } + else + { + message = replaceAll(message,L"{*SOURCE*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + } + break; + case ChatPacket::e_ChatDeathThrown: + message=app.GetString(IDS_DEATH_THROWN); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) + { + message = replaceAll(message,L"{*SOURCE*}",sourceDisplayName); + } + else + { + message = replaceAll(message,L"{*SOURCE*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + } + break; + case ChatPacket::e_ChatDeathIndirectMagic: + message=app.GetString(IDS_DEATH_INDIRECT_MAGIC); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) + { + message = replaceAll(message,L"{*SOURCE*}",sourceDisplayName); + } + else + { + message = replaceAll(message,L"{*SOURCE*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + } + break; + case ChatPacket::e_ChatDeathThorns: + message=app.GetString(IDS_DEATH_THORNS); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) + { + message = replaceAll(message,L"{*SOURCE*}",sourceDisplayName); + } + else + { + message = replaceAll(message,L"{*SOURCE*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + } + break; + case ChatPacket::e_ChatPlayerEnteredEnd: + message=app.GetString(IDS_PLAYER_ENTERED_END); + iPos=message.find(L"%s"); + message.replace(iPos,2,playerDisplayName); + break; + case ChatPacket::e_ChatPlayerLeftEnd: + message=app.GetString(IDS_PLAYER_LEFT_END); + iPos=message.find(L"%s"); + message.replace(iPos,2,playerDisplayName); + break; + + case ChatPacket::e_ChatPlayerMaxEnemies: + message=app.GetString(IDS_MAX_ENEMIES_SPAWNED); + break; + // Spawn eggs + case ChatPacket::e_ChatPlayerMaxVillagers: + message=app.GetString(IDS_MAX_VILLAGERS_SPAWNED); + break; + case ChatPacket::e_ChatPlayerMaxPigsSheepCows: + message=app.GetString(IDS_MAX_PIGS_SHEEP_COWS_CATS_SPAWNED); + break; + case ChatPacket::e_ChatPlayerMaxChickens: + message=app.GetString(IDS_MAX_CHICKENS_SPAWNED); + break; + case ChatPacket::e_ChatPlayerMaxSquid: + message=app.GetString(IDS_MAX_SQUID_SPAWNED); + break; + case ChatPacket::e_ChatPlayerMaxMooshrooms: + message=app.GetString(IDS_MAX_MOOSHROOMS_SPAWNED); + break; + case ChatPacket::e_ChatPlayerMaxWolves: + message=app.GetString(IDS_MAX_WOLVES_SPAWNED); + break; + + // Breeding + case ChatPacket::e_ChatPlayerMaxBredPigsSheepCows: + message=app.GetString(IDS_MAX_PIGS_SHEEP_COWS_CATS_BRED); + break; + case ChatPacket::e_ChatPlayerMaxBredChickens: + message=app.GetString(IDS_MAX_CHICKENS_BRED); + break; + case ChatPacket::e_ChatPlayerMaxBredMooshrooms: + message=app.GetString(IDS_MAX_MUSHROOMCOWS_BRED); + break; + + case ChatPacket::e_ChatPlayerMaxBredWolves: + message=app.GetString(IDS_MAX_WOLVES_BRED); + break; + + // can't shear the mooshroom + case ChatPacket::e_ChatPlayerCantShearMooshroom: + message=app.GetString(IDS_CANT_SHEAR_MOOSHROOM); + break; + + // Paintings/Item Frames + case ChatPacket::e_ChatPlayerMaxHangingEntities: + message=app.GetString(IDS_MAX_HANGINGENTITIES); + break; + // Enemy spawn eggs in peaceful + case ChatPacket::e_ChatPlayerCantSpawnInPeaceful: + message=app.GetString(IDS_CANT_SPAWN_IN_PEACEFUL); + break; + + // Enemy spawn eggs in peaceful + case ChatPacket::e_ChatPlayerMaxBoats: + message=app.GetString(IDS_MAX_BOATS); + break; + + case ChatPacket::e_ChatCommandTeleportSuccess: + message=app.GetString(IDS_COMMAND_TELEPORT_SUCCESS); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + if(packet->m_intArgs[0] == eTYPE_SERVERPLAYER) + { + message = replaceAll(message,L"{*DESTINATION*}",packet->m_stringArgs[1]); + } + else + { + message = replaceAll(message,L"{*DESTINATION*}",app.getEntityName((eINSTANCEOF)packet->m_intArgs[0])); + } + break; + case ChatPacket::e_ChatCommandTeleportMe: + message=app.GetString(IDS_COMMAND_TELEPORT_ME); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + case ChatPacket::e_ChatCommandTeleportToMe: + message=app.GetString(IDS_COMMAND_TELEPORT_TO_ME); + message = replaceAll(message,L"{*PLAYER*}",playerDisplayName); + break; + + default: + message = playerDisplayName; + break; + } + + // flag that a message is a death message + bool bIsDeathMessage = (packet->m_messageType>=ChatPacket::e_ChatDeathInFire) && (packet->m_messageType<=ChatPacket::e_ChatDeathDragonBreath); + + if( displayOnGui ) minecraft->gui->addMessage(message,m_userIndex, bIsDeathMessage); +} + +void ClientConnection::handleAnimate(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + if (packet->action == AnimatePacket::SWING) + { + shared_ptr player = dynamic_pointer_cast(e); + if(player != NULL) player->swing(); + } + else if (packet->action == AnimatePacket::HURT) + { + e->animateHurt(); + } + else if (packet->action == AnimatePacket::WAKE_UP) + { + shared_ptr player = dynamic_pointer_cast(e); + if(player != NULL) player->stopSleepInBed(false, false, false); + } + else if (packet->action == AnimatePacket::RESPAWN) + { + } + else if (packet->action == AnimatePacket::CRITICAL_HIT) + { + shared_ptr critParticle = shared_ptr( new CritParticle(minecraft->level, e) ); + critParticle->CritParticlePostConstructor(); + minecraft->particleEngine->add( critParticle ); + } + else if (packet->action == AnimatePacket::MAGIC_CRITICAL_HIT) + { + shared_ptr critParticle = shared_ptr( new CritParticle(minecraft->level, e, eParticleType_magicCrit) ); + critParticle->CritParticlePostConstructor(); + minecraft->particleEngine->add(critParticle); + } + else if (packet->action == AnimatePacket::EAT && dynamic_pointer_cast(e) != NULL) + { + } + +} + +void ClientConnection::handleEntityActionAtPosition(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + if (packet->action == EntityActionAtPositionPacket::START_SLEEP) + { + shared_ptr player = dynamic_pointer_cast(e); + player->startSleepInBed(packet->x, packet->y, packet->z); + + if( player == minecraft->localplayers[m_userIndex] ) + { + TelemetryManager->RecordEnemyKilledOrOvercome(m_userIndex, 0, player->y, 0, 0, 0, 0, eTelemetryInGame_UseBed); + } + } +} + +void ClientConnection::handlePreLogin(shared_ptr packet) +{ +// printf("Client: handlePreLogin\n"); +#if 1 + // 4J - Check that we can play with all the players already in the game who have Friends-Only UGC set + BOOL canPlay = TRUE; + BOOL canPlayLocal = TRUE; + BOOL isAtLeastOneFriend = g_NetworkManager.IsHost(); + BOOL isFriendsWithHost = TRUE; + BOOL cantPlayContentRestricted = FALSE; + + if(!g_NetworkManager.IsHost()) + { + // set the game host settings + app.SetGameHostOption(eGameHostOption_All,packet->m_serverSettings); + + // 4J-PB - if we go straight in from the menus via an invite, we won't have the DLC info + if(app.GetTMSGlobalFileListRead()==false) + { + app.SetTMSAction(ProfileManager.GetPrimaryPad(),eTMSAction_TMSPP_RetrieveFiles_RunPlayGame); + } + } + +#ifdef _XBOX + if(!g_NetworkManager.IsHost() && !app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) + { + if(m_userIndex == ProfileManager.GetPrimaryPad() ) + { + for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if(ProfileManager.IsSignedIn(m_userIndex) && ProfileManager.IsGuest(idx)) + { + canPlay = FALSE; + isFriendsWithHost = FALSE; + } + else + { + PlayerUID playerXuid = INVALID_XUID; + if( ProfileManager.IsSignedInLive(idx) ) + { + ProfileManager.GetXUID(idx,&playerXuid,true); + } + if( playerXuid != INVALID_XUID ) + { + // Is this user friends with the host player? + BOOL result; + DWORD error; + error = XUserAreUsersFriends(idx,&packet->m_playerXuids[packet->m_hostIndex],1,&result,NULL); + if(error == ERROR_SUCCESS && result != TRUE) + { + canPlay = FALSE; + isFriendsWithHost = FALSE; + } + } + } + if(!canPlay) break; + } + } + else + { + if(ProfileManager.IsSignedIn(m_userIndex) && ProfileManager.IsGuest(m_userIndex)) + { + canPlay = FALSE; + isFriendsWithHost = FALSE; + } + else + { + PlayerUID playerXuid = INVALID_XUID; + if( ProfileManager.IsSignedInLive(m_userIndex) ) + { + ProfileManager.GetXUID(m_userIndex,&playerXuid,true); + } + if( playerXuid != INVALID_XUID ) + { + // Is this user friends with the host player? + BOOL result; + DWORD error; + error = XUserAreUsersFriends(m_userIndex,&packet->m_playerXuids[packet->m_hostIndex],1,&result,NULL); + if(error == ERROR_SUCCESS && result != TRUE) + { + canPlay = FALSE; + isFriendsWithHost = FALSE; + } + } + } + } + } + + if( canPlay ) + { + for(DWORD i = 0; i < packet->m_dwPlayerCount; ++i) + { + bool localPlayer = false; + for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if( ProfileManager.IsSignedInLive(idx) ) + { + // need to use the XUID here + PlayerUID playerXUID = INVALID_XUID; + if( !ProfileManager.IsGuest( idx ) ) + { + // Guest don't have an offline XUID as they cannot play offline, so use their online one + ProfileManager.GetXUID(idx,&playerXUID,true); + } + if( ProfileManager.AreXUIDSEqual(playerXUID,packet->m_playerXuids[i]) ) localPlayer = true; + } + else if (ProfileManager.IsSignedIn(idx)) + { + // If we aren't signed into live then they have to be a local player + localPlayer = true; + } + } + if(!localPlayer) + { + // First check our own permissions to see if we can play with this player + if(m_userIndex == ProfileManager.GetPrimaryPad() ) + { + canPlayLocal = ProfileManager.CanViewPlayerCreatedContent(m_userIndex,false,&packet->m_playerXuids[i],1); + + // 4J Stu - Everyone joining needs to have at least one friend in the game + // Local players are implied friends + if( isAtLeastOneFriend != TRUE ) + { + BOOL result; + DWORD error; + for(DWORD idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if( ProfileManager.IsSignedIn(idx) && !ProfileManager.IsGuest(idx) ) + { + error = XUserAreUsersFriends(idx,&packet->m_playerXuids[i],1,&result,NULL); + if(error == ERROR_SUCCESS && result == TRUE) isAtLeastOneFriend = TRUE; + } + } + } + } + else + { + // Friends with the primary player on this system + isAtLeastOneFriend = true; + + canPlayLocal = ProfileManager.CanViewPlayerCreatedContent(m_userIndex,true,&packet->m_playerXuids[i],1); + } + + // If we can play with them, then check if they can play with us + if( canPlayLocal && ( packet->m_friendsOnlyBits & (1<m_playerXuids[i],1,&result,NULL); + if(error == ERROR_SUCCESS) canPlay &= result; + } + if(!canPlay) break; + } + } + if(!canPlay || !canPlayLocal) break; + } + } + } +#else + // TODO - handle this kind of things for non-360 platforms + canPlay = TRUE; + canPlayLocal = TRUE; + isAtLeastOneFriend = TRUE; + cantPlayContentRestricted= FALSE; + +#if ( defined __PS3__ || defined __ORBIS__ || defined __PSVITA__) + + if(!g_NetworkManager.IsHost() && !app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) + { + bool bChatRestricted=false; + + ProfileManager.GetChatAndContentRestrictions(m_userIndex,true,&bChatRestricted,NULL,NULL); + + // Chat restricted orbis players can still play online +#ifndef __ORBIS__ + canPlay = !bChatRestricted; +#endif + + if(m_userIndex == ProfileManager.GetPrimaryPad() ) + { + // Is this user friends with the host player? + bool isFriend = true; + unsigned int friendCount = 0; +#ifdef __PS3__ + int ret = sceNpBasicGetFriendListEntryCount(&friendCount); +#elif defined __PSVITA__ + sce::Toolkit::NP::Utilities::Future friendList; + int ret = -1; + if(!CGameNetworkManager::usingAdhocMode()) // we don't need to be friends in PSN for adhoc mode + { + int ret = sce::Toolkit::NP::Friends::Interface::getFriendslist(&friendList, false); + if(ret == SCE_TOOLKIT_NP_SUCCESS) + { + if( friendList.hasResult() ) + { + friendCount = friendList.get()->size(); + } + } + } +#else // __ORBIS__ + + sce::Toolkit::NP::Utilities::Future friendList; + + sce::Toolkit::NP::FriendInfoRequest requestParam; + memset(&requestParam,0,sizeof(requestParam)); + requestParam.flag = SCE_TOOLKIT_NP_FRIENDS_LIST_ALL; + requestParam.limit = 0; + requestParam.offset = 0; + requestParam.userInfo.userId = ProfileManager.getUserID(ProfileManager.GetPrimaryPad()); + + int ret = sce::Toolkit::NP::Friends::Interface::getFriendslist(&friendList, &requestParam, false); + if( ret == 0 ) + { + if( friendList.hasResult() ) + { + friendCount = friendList.get()->size(); + } + } +#endif + if( ret == 0 ) + { + isFriend = false; + SceNpId npid; + for( unsigned int i = 0; i < friendCount; i++ ) + { +#ifdef __PS3__ + ret = sceNpBasicGetFriendListEntry( i, &npid ); +#else + npid = friendList.get()->at(i).npid; +#endif + if( ret == 0 ) + { + if(strcmp(npid.handle.data, packet->m_playerXuids[packet->m_hostIndex].getOnlineID()) == 0) + { + isFriend = true; + break; + } + } + } + } + + if( !isFriend ) + { + canPlay = FALSE; + isFriendsWithHost = FALSE; + } + } + } + // is it an online game, and a player has chat restricted? + else if(!g_NetworkManager.IsLocalGame()) + { + // if the player is chat restricted, then they can't play an online game + bool bChatRestricted=false; + bool bContentRestricted=false; + + // If this is a pre-login packet for the first player on the machine, then accumulate up these flags for everyone signed in. We can handle exiting the game + // much more cleanly at this point by exiting the level, rather than waiting for a prelogin packet for the other players, when we have to exit the player + // which seems to be very unstable at the point of starting up the game + if(m_userIndex == ProfileManager.GetPrimaryPad()) + { + ProfileManager.GetChatAndContentRestrictions(m_userIndex,false,&bChatRestricted,&bContentRestricted,NULL); + } + else + { + ProfileManager.GetChatAndContentRestrictions(m_userIndex,true,&bChatRestricted,&bContentRestricted,NULL); + } + + // Chat restricted orbis players can still play online +#ifndef __ORBIS__ + canPlayLocal = !bChatRestricted; +#endif + + cantPlayContentRestricted = bContentRestricted ? 1 : 0; + } + + +#endif + +#ifdef _XBOX_ONE + if(!g_NetworkManager.IsHost() && m_userIndex == ProfileManager.GetPrimaryPad()) + { + long long startTime = System::currentTimeMillis(); + + auto friendsXuids = DQRNetworkManager::GetFriends(); + + if (app.GetGameHostOption(eGameHostOption_FriendsOfFriends)) + { + // Check that the user has at least one friend in the game + isAtLeastOneFriend = false; + + for (int i = 0; i < friendsXuids->Size; i++) + { + auto friendsXuid = friendsXuids->GetAt(i); + + // Check this friend against each player, if we find them we have at least one friend + for (int j = 0; j < g_NetworkManager.GetPlayerCount(); j++) + { + Platform::String^ xboxUserId = ref new Platform::String(g_NetworkManager.GetPlayerByIndex(j)->GetUID().toString().data()); + if (friendsXuid == xboxUserId) + { + isAtLeastOneFriend = true; + break; + } + } + } + + app.DebugPrintf("ClientConnection::handlePreLogin: User has at least one friend? %s\n", isAtLeastOneFriend ? "Yes" : "No"); + } + else + { + // Check that the user is friends with the host + bool isFriend = false; + + Platform::String^ hostXboxUserId = ref new Platform::String(g_NetworkManager.GetHostPlayer()->GetUID().toString().data()); + + for (int i = 0; i < friendsXuids->Size; i++) + { + if (friendsXuids->GetAt(i) == hostXboxUserId) + { + isFriend = true; + break; + } + } + + if( !isFriend ) + { + canPlay = FALSE; + isFriendsWithHost = FALSE; + } + + app.DebugPrintf("ClientConnection::handlePreLogin: User is friends with the host? %s\n", isFriendsWithHost ? "Yes" : "No"); + } + + app.DebugPrintf("ClientConnection::handlePreLogin: Friendship checks took %i ms\n", System::currentTimeMillis() - startTime); + } +#endif + +#endif // _XBOX + + if(!canPlay || !canPlayLocal || !isAtLeastOneFriend || cantPlayContentRestricted) + { +#ifndef __PS3__ + DisconnectPacket::eDisconnectReason reason = DisconnectPacket::eDisconnect_NoUGC_Remote; +#else + DisconnectPacket::eDisconnectReason reason = DisconnectPacket::eDisconnect_None; +#endif + if(m_userIndex == ProfileManager.GetPrimaryPad()) + { + if(!isFriendsWithHost) reason = DisconnectPacket::eDisconnect_NotFriendsWithHost; + else if(!isAtLeastOneFriend) reason = DisconnectPacket::eDisconnect_NoFriendsInGame; + else if(!canPlayLocal) reason = DisconnectPacket::eDisconnect_NoUGC_AllLocal; + else if(cantPlayContentRestricted) reason = DisconnectPacket::eDisconnect_ContentRestricted_AllLocal; + + app.DebugPrintf("Exiting world on handling Pre-Login packet due UGC privileges: %d\n", reason); + app.SetDisconnectReason( reason ); + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE); + } + else + { + if(!isFriendsWithHost) reason = DisconnectPacket::eDisconnect_NotFriendsWithHost; + else if(!canPlayLocal) reason = DisconnectPacket::eDisconnect_NoUGC_Single_Local; + else if(cantPlayContentRestricted) reason = DisconnectPacket::eDisconnect_ContentRestricted_Single_Local; + + app.DebugPrintf("Exiting player %d on handling Pre-Login packet due UGC privileges: %d\n", m_userIndex, reason); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + if(!isFriendsWithHost) ui.RequestMessageBox( IDS_CANTJOIN_TITLE, IDS_NOTALLOWED_FRIENDSOFFRIENDS, uiIDA,1,m_userIndex,NULL,NULL, app.GetStringTable()); + else ui.RequestMessageBox( IDS_CANTJOIN_TITLE, IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL, uiIDA,1,m_userIndex,NULL,NULL, app.GetStringTable()); + + app.SetDisconnectReason( reason ); + + // 4J-PB - this locks up on the read and write threads not closing down, because they are trying to lock the incoming critsec when it's already locked by this thread +// Minecraft::GetInstance()->connectionDisconnected( m_userIndex , reason ); +// done = true; +// connection->flush(); +// connection->close(reason); +// app.SetAction(m_userIndex,eAppAction_ExitPlayer); + + // 4J-PB - doing this instead + app.SetAction(m_userIndex,eAppAction_ExitPlayerPreLogin); + } + } + else + { + // Texture pack handling + // If we have the texture pack for the game, load it + // If we don't then send a packet to the host to request it. We need to send this before the LoginPacket so that it gets handled first, + // as once the LoginPacket is received on the client the game is close to starting + if(m_userIndex == ProfileManager.GetPrimaryPad()) + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + if( pMinecraft->skins->selectTexturePackById(packet->m_texturePackId) ) + { + app.DebugPrintf("Selected texture pack %d from Pre-Login packet\n", packet->m_texturePackId); + } + else + { + app.DebugPrintf("Could not select texture pack %d from Pre-Login packet, requesting from host\n", packet->m_texturePackId); + + // 4J-PB - we need to upsell the texture pack to the player + //app.SetAction(m_userIndex,eAppAction_TexturePackRequired); + // Let the player go into the game, and we'll check that they are using the right texture pack when in + } + } + + if(!g_NetworkManager.IsHost() ) + { + Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCPreLoginReceived * 100)/ (eCCConnected)); + } + // need to use the XUID here + PlayerUID offlineXUID = INVALID_XUID; + PlayerUID onlineXUID = INVALID_XUID; + if( ProfileManager.IsSignedInLive(m_userIndex) ) + { + // Guest don't have an offline XUID as they cannot play offline, so use their online one + ProfileManager.GetXUID(m_userIndex,&onlineXUID,true); + } +#ifdef __PSVITA__ + if(CGameNetworkManager::usingAdhocMode() && onlineXUID.getOnlineID()[0] == 0) + { + // player doesn't have an online UID, set it from the player name + onlineXUID.setForAdhoc(); + } +#endif + + // On PS3, all non-signed in players (even guests) can get a useful offlineXUID +#if !(defined __PS3__ || defined _DURANGO ) + if( !ProfileManager.IsGuest( m_userIndex ) ) +#endif + { + // All other players we use their offline XUID so that they can play the game offline + ProfileManager.GetXUID(m_userIndex,&offlineXUID,false); + } + BOOL allAllowed, friendsAllowed; + ProfileManager.AllowedPlayerCreatedContent(m_userIndex,true,&allAllowed,&friendsAllowed); + send( shared_ptr( new LoginPacket(minecraft->user->name, SharedConstants::NETWORK_PROTOCOL_VERSION, offlineXUID, onlineXUID, (allAllowed!=TRUE && friendsAllowed==TRUE), + packet->m_ugcPlayersVersion, app.GetPlayerSkinId(m_userIndex), app.GetPlayerCapeId(m_userIndex), ProfileManager.IsGuest( m_userIndex )))); + + if(!g_NetworkManager.IsHost() ) + { + Minecraft::GetInstance()->progressRenderer->progressStagePercentage((eCCLoginSent * 100)/ (eCCConnected)); + } + } +#else + // 4J - removed + if (packet->loginKey.equals("-")) { + send(new LoginPacket(minecraft->user.name, SharedConstants.NETWORK_PROTOCOL_VERSION)); + } else { + try { + URL url = new URL("http://www.minecraft->net/game/joinserver.jsp?user=" + minecraft->user.name + "&sessionId=" + minecraft->user.sessionId + "&serverId=" + packet->loginKey); + BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream())); + String msg = br.readLine(); + br.close(); + + if (msg.equalsIgnoreCase("ok")) { + send(new LoginPacket(minecraft->user.name, SharedConstants.NETWORK_PROTOCOL_VERSION)); + } else { + connection.close("disconnect.loginFailedInfo", msg); + } + } catch (Exception e) { + e.printStackTrace(); + connection.close("disconnect.genericReason", "Internal client error: " + e.toString()); + } + } +#endif +} + +void ClientConnection::close() +{ + // If it's already done, then we don't need to do anything here. And in fact trying to do something could cause a crash + if(done) return; + done = true; + connection->flush(); + connection->close(DisconnectPacket::eDisconnect_Closed); +} + +void ClientConnection::handleAddMob(shared_ptr packet) +{ + double x = packet->x / 32.0; + double y = packet->y / 32.0; + double z = packet->z / 32.0; + float yRot = packet->yRot * 360 / 256.0f; + float xRot = packet->xRot * 360 / 256.0f; + + shared_ptr mob = dynamic_pointer_cast(EntityIO::newById(packet->type, level)); + mob->xp = packet->x; + mob->yp = packet->y; + mob->zp = packet->z; + mob->yHeadRot = packet->yHeadRot * 360 / 256.0f; + mob->yRotp = packet->yRot; + mob->xRotp = packet->xRot; + + vector > *subEntities = mob->getSubEntities(); + if (subEntities != NULL) + { + int offs = packet->id - mob->entityId; + //for (int i = 0; i < subEntities.length; i++) + for(AUTO_VAR(it, subEntities->begin()); it != subEntities->end(); ++it) + { + //subEntities[i].entityId += offs; + (*it)->entityId += offs; + } + } + + mob->entityId = packet->id; + +// printf("\t\t\t\t%d: Add mob rot %d\n",packet->id,packet->yRot); + + mob->absMoveTo(x, y, z, yRot, xRot); + mob->xd = packet->xd / 8000.0f; + mob->yd = packet->yd / 8000.0f; + mob->zd = packet->zd / 8000.0f; + level->putEntity(packet->id, mob); + + vector > *unpackedData = packet->getUnpackedData(); + if (unpackedData != NULL) + { + mob->getEntityData()->assignValues(unpackedData); + } + + // Fix for #65236 - TU8: Content: Gameplay: Magma Cubes' have strange hit boxes. + // 4J Stu - Slimes have a different BB depending on their size which is set in the entity data, so update the BB + if(mob->GetType() == eTYPE_SLIME || mob->GetType() == eTYPE_LAVASLIME) + { + shared_ptr slime = dynamic_pointer_cast(mob); + slime->setSize( slime->getSize() ); + } +} + +void ClientConnection::handleSetTime(shared_ptr packet) +{ + minecraft->level->setTime(packet->time); +} + +void ClientConnection::handleSetSpawn(shared_ptr packet) +{ + //minecraft->player->setRespawnPosition(new Pos(packet->x, packet->y, packet->z)); + minecraft->localplayers[m_userIndex]->setRespawnPosition(new Pos(packet->x, packet->y, packet->z)); + minecraft->level->getLevelData()->setSpawn(packet->x, packet->y, packet->z); + +} + +void ClientConnection::handleRidePacket(shared_ptr packet) +{ + shared_ptr rider = getEntity(packet->riderId); + shared_ptr ridden = getEntity(packet->riddenId); + + shared_ptr boat = dynamic_pointer_cast(ridden); + //if (packet->riderId == minecraft->player->entityId) rider = minecraft->player; + if (packet->riderId == minecraft->localplayers[m_userIndex]->entityId) + { + rider = minecraft->localplayers[m_userIndex]; + + if (boat) boat->setDoLerp(false); + } + else if (boat) + { + boat->setDoLerp(true); + } + if (rider == NULL) return; + + rider->ride(ridden); +} + +void ClientConnection::handleEntityEvent(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->entityId); + if (e != NULL) e->handleEntityEvent(packet->eventId); +} + +shared_ptr ClientConnection::getEntity(int entityId) +{ + //if (entityId == minecraft->player->entityId) + if(entityId == minecraft->localplayers[m_userIndex]->entityId) + { + //return minecraft->player; + return minecraft->localplayers[m_userIndex]; + } + return level->getEntity(entityId); +} + +void ClientConnection::handleSetHealth(shared_ptr packet) +{ + //minecraft->player->hurtTo(packet->health); + minecraft->localplayers[m_userIndex]->hurtTo(packet->health,packet->damageSource); + minecraft->localplayers[m_userIndex]->getFoodData()->setFoodLevel(packet->food); + minecraft->localplayers[m_userIndex]->getFoodData()->setSaturation(packet->saturation); + + // We need food + if(packet->food < FoodConstants::HEAL_LEVEL - 1) + { + if(minecraft->localgameModes[m_userIndex] != NULL && !minecraft->localgameModes[m_userIndex]->hasInfiniteItems() ) + { + minecraft->localgameModes[m_userIndex]->getTutorial()->changeTutorialState(e_Tutorial_State_Food_Bar); + } + } +} + +void ClientConnection::handleSetExperience(shared_ptr packet) +{ + minecraft->localplayers[m_userIndex]->setExperienceValues(packet->experienceProgress, packet->totalExperience, packet->experienceLevel); +} + +void ClientConnection::handleTexture(shared_ptr packet) +{ + // Both PlayerConnection and ClientConnection should handle this mostly the same way + // Server side also needs to store a list of those clients waiting to get a texture the server doesn't have yet + // so that it can send it out to them when it comes in + + if(packet->dwBytes==0) + { + // Request for texture +#ifndef _CONTENT_PACKAGE + wprintf(L"Client received request for custom texture %ls\n",packet->textureName.c_str()); +#endif + PBYTE pbData=NULL; + DWORD dwBytes=0; + app.GetMemFileDetails(packet->textureName,&pbData,&dwBytes); + + if(dwBytes!=0) + { + send( shared_ptr( new TexturePacket(packet->textureName,pbData,dwBytes) ) ); + } + } + else + { + // Response with texture data +#ifndef _CONTENT_PACKAGE + wprintf(L"Client received custom texture %ls\n",packet->textureName.c_str()); +#endif + app.AddMemoryTextureFile(packet->textureName,packet->pbData,packet->dwBytes); + Minecraft::GetInstance()->handleClientTextureReceived(packet->textureName); + } +} + +void ClientConnection::handleTextureAndGeometry(shared_ptr packet) +{ + // Both PlayerConnection and ClientConnection should handle this mostly the same way + // Server side also needs to store a list of those clients waiting to get a texture the server doesn't have yet + // so that it can send it out to them when it comes in + + if(packet->dwTextureBytes==0) + { + // Request for texture +#ifndef _CONTENT_PACKAGE + wprintf(L"Client received request for custom texture and geometry %ls\n",packet->textureName.c_str()); +#endif + PBYTE pbData=NULL; + DWORD dwBytes=0; + app.GetMemFileDetails(packet->textureName,&pbData,&dwBytes); + DLCSkinFile *pDLCSkinFile = app.m_dlcManager.getSkinFile(packet->textureName); + + if(dwBytes!=0) + { + if(pDLCSkinFile) + { + if(pDLCSkinFile->getAdditionalBoxesCount()!=0) + { + send( shared_ptr( new TextureAndGeometryPacket(packet->textureName,pbData,dwBytes,pDLCSkinFile) ) ); + } + else + { + send( shared_ptr( new TextureAndGeometryPacket(packet->textureName,pbData,dwBytes) ) ); + } + } + else + { + unsigned int uiAnimOverrideBitmask= app.GetAnimOverrideBitmask(packet->dwSkinID); + + send( shared_ptr( new TextureAndGeometryPacket(packet->textureName,pbData,dwBytes,app.GetAdditionalSkinBoxes(packet->dwSkinID),uiAnimOverrideBitmask) ) ); + } + } + } + else + { + // Response with texture data +#ifndef _CONTENT_PACKAGE + wprintf(L"Client received custom TextureAndGeometry %ls\n",packet->textureName.c_str()); +#endif + // Add the texture data + app.AddMemoryTextureFile(packet->textureName,packet->pbData,packet->dwTextureBytes); + // Add the geometry data + if(packet->dwBoxC!=0) + { + app.SetAdditionalSkinBoxes(packet->dwSkinID,packet->BoxDataA,packet->dwBoxC); + } + // Add the anim override + app.SetAnimOverrideBitmask(packet->dwSkinID,packet->uiAnimOverrideBitmask); + + // clear out the pending texture request + Minecraft::GetInstance()->handleClientTextureReceived(packet->textureName); + } +} + +void ClientConnection::handleTextureChange(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + shared_ptr player = dynamic_pointer_cast(e); + if( e == NULL) return; + + bool isLocalPlayer = false; + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + if( minecraft->localplayers[i] ) + { + if( minecraft->localplayers[i]->entityId == packet->id ) + { + isLocalPlayer = true; + break; + } + } + } + if(isLocalPlayer) return; + + switch(packet->action) + { + case TextureChangePacket::e_TextureChange_Skin: + player->setCustomSkin( app.getSkinIdFromPath( packet->path ) ); +#ifndef _CONTENT_PACKAGE + wprintf(L"Skin for remote player %ls has changed to %ls (%d)\n", player->name.c_str(), player->customTextureUrl.c_str(), player->getPlayerDefaultSkin() ); +#endif + break; + case TextureChangePacket::e_TextureChange_Cape: + player->setCustomCape( Player::getCapeIdFromPath( packet->path ) ); + //player->customTextureUrl2 = packet->path; +#ifndef _CONTENT_PACKAGE + wprintf(L"Cape for remote player %ls has changed to %ls\n", player->name.c_str(), player->customTextureUrl2.c_str() ); +#endif + break; + } + + if(!packet->path.empty() && packet->path.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(packet->path)) + { + if( minecraft->addPendingClientTextureRequest(packet->path) ) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"handleTextureChange - Client sending texture packet to get custom skin %ls for player %ls\n",packet->path.c_str(), player->name.c_str()); +#endif + send(shared_ptr( new TexturePacket(packet->path,NULL,0) ) ); + } + } + else if(!packet->path.empty() && app.IsFileInMemoryTextures(packet->path)) + { + // Update the ref count on the memory texture data + app.AddMemoryTextureFile(packet->path,NULL,0); + } +} + +void ClientConnection::handleTextureAndGeometryChange(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->id); + if (e == NULL) return; + shared_ptr player = dynamic_pointer_cast(e); + if( e == NULL) return; + + bool isLocalPlayer = false; + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + if( minecraft->localplayers[i] ) + { + if( minecraft->localplayers[i]->entityId == packet->id ) + { + isLocalPlayer = true; + break; + } + } + } + if(isLocalPlayer) return; + + + player->setCustomSkin( app.getSkinIdFromPath( packet->path ) ); + +#ifndef _CONTENT_PACKAGE + wprintf(L"Skin for remote player %ls has changed to %ls (%d)\n", player->name.c_str(), player->customTextureUrl.c_str(), player->getPlayerDefaultSkin() ); +#endif + + if(!packet->path.empty() && packet->path.substr(0,3).compare(L"def") != 0 && !app.IsFileInMemoryTextures(packet->path)) + { + if( minecraft->addPendingClientTextureRequest(packet->path) ) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"handleTextureAndGeometryChange - Client sending TextureAndGeometryPacket to get custom skin %ls for player %ls\n",packet->path.c_str(), player->name.c_str()); +#endif + send(shared_ptr( new TextureAndGeometryPacket(packet->path,NULL,0) ) ); + } + } + else if(!packet->path.empty() && app.IsFileInMemoryTextures(packet->path)) + { + // Update the ref count on the memory texture data + app.AddMemoryTextureFile(packet->path,NULL,0); + + } +} + +void ClientConnection::handleRespawn(shared_ptr packet) +{ + //if (packet->dimension != minecraft->player->dimension) + if( packet->dimension != minecraft->localplayers[m_userIndex]->dimension || packet->mapSeed != minecraft->localplayers[m_userIndex]->level->getSeed() ) + { + int oldDimension = minecraft->localplayers[m_userIndex]->dimension; + started = false; + + // Remove client connection from this level + level->removeClientConnection(this, false); + + MultiPlayerLevel *dimensionLevel = (MultiPlayerLevel *)minecraft->getLevel( packet->dimension ); + if( dimensionLevel == NULL ) + { + dimensionLevel = new MultiPlayerLevel(this, new LevelSettings(packet->mapSeed, packet->playerGameType, false, minecraft->level->getLevelData()->isHardcore(), packet->m_newSeaLevel, packet->m_pLevelType, packet->m_xzSize, packet->m_hellScale), packet->dimension, packet->difficulty); + + // 4J Stu - We want to shared the savedDataStorage between both levels + //if( dimensionLevel->savedDataStorage != NULL ) + //{ + // Don't need to delete it here as it belongs to a client connection while will delete it when it's done + // delete dimensionLevel->savedDataStorage;+ + //} + dimensionLevel->savedDataStorage = level->savedDataStorage; + + dimensionLevel->difficulty = packet->difficulty; // 4J Added + app.DebugPrintf("dimensionLevel->difficulty - Difficulty = %d\n",packet->difficulty); + + dimensionLevel->isClientSide = true; + } + else + { + dimensionLevel->addClientConnection(this); + } + + // Remove the player entity from the current level + level->removeEntity( shared_ptr(minecraft->localplayers[m_userIndex]) ); + + level = dimensionLevel; + + // Whilst calling setLevel, make sure that minecraft::player is set up to be correct for this + // connection + shared_ptr lastPlayer = minecraft->player; + minecraft->player = minecraft->localplayers[m_userIndex]; + minecraft->setLevel(dimensionLevel); + minecraft->player = lastPlayer; + + TelemetryManager->RecordLevelExit(m_userIndex, eSen_LevelExitStatus_Succeeded); + + //minecraft->player->dimension = packet->dimension; + minecraft->localplayers[m_userIndex]->dimension = packet->dimension; + //minecraft->setScreen(new ReceivingLevelScreen(this)); +// minecraft->addPendingLocalConnection(m_userIndex, this); + +#ifdef _XBOX + TelemetryManager->RecordLevelStart(m_userIndex, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->getLevel(packet->dimension)->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount()); +#endif + + if( minecraft->localgameModes[m_userIndex] != NULL ) + { + TutorialMode *gameMode = (TutorialMode *)minecraft->localgameModes[m_userIndex]; + gameMode->getTutorial()->showTutorialPopup(false); + } + + // 4J-JEV: Fix for Durango #156334 - Content: UI: Rich Presence 'In the Nether' message is updating with a 3 to 10 minute delay. + minecraft->localplayers[m_userIndex]->updateRichPresence(); + + ConnectionProgressParams *param = new ConnectionProgressParams(); + param->iPad = m_userIndex; + if( packet->dimension == -1) + { + param->stringId = IDS_PROGRESS_ENTERING_NETHER; + } + else if( oldDimension == -1) + { + param->stringId = IDS_PROGRESS_LEAVING_NETHER; + } + else if( packet->dimension == 1) + { + param->stringId = IDS_PROGRESS_ENTERING_END; + } + else if( oldDimension == 1) + { + param->stringId = IDS_PROGRESS_LEAVING_END; + } + param->showTooltips = false; + param->setFailTimer = false; + + // 4J Stu - Fix for #13543 - Crash: Game crashes if entering a portal with the inventory menu open + ui.CloseUIScenes( m_userIndex ); + + if(app.GetLocalPlayerCount()>1) + { + ui.NavigateToScene(m_userIndex, eUIScene_ConnectingProgress, param); + } + else + { + ui.NavigateToScene(m_userIndex, eUIScene_ConnectingProgress, param); + } + + app.SetAction( m_userIndex, eAppAction_WaitForDimensionChangeComplete); + } + + //minecraft->respawnPlayer(minecraft->player->GetXboxPad(),true, packet->dimension); + + // Wrap respawnPlayer call up in code to set & restore the player/gamemode etc. as some things + // in there assume that we are set up for the player that the respawn is coming in for + int oldIndex = minecraft->getLocalPlayerIdx(); + minecraft->setLocalPlayerIdx(m_userIndex); + minecraft->respawnPlayer(minecraft->localplayers[m_userIndex]->GetXboxPad(),packet->dimension,packet->m_newEntityId); + ((MultiPlayerGameMode *) minecraft->localgameModes[m_userIndex])->setLocalMode(packet->playerGameType); + minecraft->setLocalPlayerIdx(oldIndex); +} + +void ClientConnection::handleExplosion(shared_ptr packet) +{ + if(!packet->m_bKnockbackOnly) + { + //app.DebugPrintf("Received ExplodePacket with explosion data\n"); + PIXBeginNamedEvent(0,"Handling explosion"); + Explosion *e = new Explosion(minecraft->level, nullptr, packet->x, packet->y, packet->z, packet->r); + PIXBeginNamedEvent(0,"Finalizing"); + + // Fix for #81758 - TCR 006 BAS Non-Interactive Pause: TU9: Performance: Gameplay: After detonating bunch of TNT, game enters unresponsive state for couple of seconds. + // The changes we are making here have been decided by the server, so we don't need to add them to the vector that resets tiles changes made + // on the client as we KNOW that the server is matching these changes + MultiPlayerLevel *mpLevel = (MultiPlayerLevel *)minecraft->level; + mpLevel->enableResetChanges(false); + // 4J - now directly pass a pointer to the toBlow array in the packet rather than copying around + e->finalizeExplosion(true, &packet->toBlow); + mpLevel->enableResetChanges(true); + PIXEndNamedEvent(); + PIXEndNamedEvent(); + delete e; + } + else + { + //app.DebugPrintf("Received ExplodePacket with knockback only data\n"); + } + + //app.DebugPrintf("Adding knockback (%f,%f,%f) for player %d\n", packet->getKnockbackX(), packet->getKnockbackY(), packet->getKnockbackZ(), m_userIndex); + minecraft->localplayers[m_userIndex]->xd += packet->getKnockbackX(); + minecraft->localplayers[m_userIndex]->yd += packet->getKnockbackY(); + minecraft->localplayers[m_userIndex]->zd += packet->getKnockbackZ(); +} + +void ClientConnection::handleContainerOpen(shared_ptr packet) +{ + bool failed = false; + shared_ptr player = minecraft->localplayers[m_userIndex]; + switch(packet->type) + { + case ContainerOpenPacket::CONTAINER: + { + if( player->openContainer(shared_ptr( new SimpleContainer(packet->title, packet->size) ))) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::FURNACE: + { + if( player->openFurnace(shared_ptr( new FurnaceTileEntity() )) ) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::BREWING_STAND: + { + if( player->openBrewingStand(shared_ptr( new BrewingStandTileEntity() )) ) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::TRAP: + { + if( player->openTrap(shared_ptr( new DispenserTileEntity() )) ) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::WORKBENCH: + { + if( player->startCrafting(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)) ) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::ENCHANTMENT: + { + if( player->startEnchanting(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z)) ) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::TRADER_NPC: + { + shared_ptr csm = shared_ptr(new ClientSideMerchant(player,packet->title)); + csm->createContainer(); + if(player->openTrading(csm)) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + case ContainerOpenPacket::REPAIR_TABLE: + { + if(player->startRepairing(Mth::floor(player->x), Mth::floor(player->y), Mth::floor(player->z))) + { + player->containerMenu->containerId = packet->containerId; + } + else + { + failed = true; + } + } + break; + }; + + if(failed) + { + // Failed - if we've got a non-inventory container currently here, close that, which locally should put us back + // to not having a container open, and should send a containerclose to the server so it doesn't have a container open. + // If we don't have a non-inventory container open, just send the packet, and again we ought to be in sync with the server. + if( player->containerMenu != player->inventoryMenu ) + { + ui.CloseUIScenes(m_userIndex); + } + else + { + send(shared_ptr(new ContainerClosePacket(packet->containerId))); + } + } +} + +void ClientConnection::handleContainerSetSlot(shared_ptr packet) +{ + shared_ptr player = minecraft->localplayers[m_userIndex]; + if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_CARRIED ) + { + player->inventory->setCarried(packet->item); + } + else + { + if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY) + { + // 4J Stu - Reworked a bit to fix a bug where things being collected while the creative menu was up replaced items in the creative menu + if(packet->slot >= 36 && packet->slot < 36 + 9) + { + shared_ptr lastItem = player->inventoryMenu->getSlot(packet->slot)->getItem(); + if (packet->item != NULL) + { + if (lastItem == NULL || lastItem->count < packet->item->count) + { + packet->item->popTime = Inventory::POP_TIME_DURATION; + } + } + } + player->inventoryMenu->setItem(packet->slot, packet->item); + } + else if (packet->containerId == player->containerMenu->containerId) + { + player->containerMenu->setItem(packet->slot, packet->item); + } + } +} + +void ClientConnection::handleContainerAck(shared_ptr packet) +{ + shared_ptr player = minecraft->localplayers[m_userIndex]; + AbstractContainerMenu *menu = NULL; + if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY) + { + menu = player->inventoryMenu; + } + else if (packet->containerId == player->containerMenu->containerId) + { + menu = player->containerMenu; + } + if (menu != NULL) + { + if (!packet->accepted) + { + send( shared_ptr( new ContainerAckPacket(packet->containerId, packet->uid, true) )); + } + } +} + +void ClientConnection::handleContainerContent(shared_ptr packet) +{ + shared_ptr player = minecraft->localplayers[m_userIndex]; + if (packet->containerId == AbstractContainerMenu::CONTAINER_ID_INVENTORY) + { + player->inventoryMenu->setAll(&packet->items); + } + else if (packet->containerId == player->containerMenu->containerId) + { + player->containerMenu->setAll(&packet->items); + } +} + +void ClientConnection::handleSignUpdate(shared_ptr packet) +{ + app.DebugPrintf("ClientConnection::handleSignUpdate - "); + if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z)) + { + shared_ptr te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z); + + // 4J-PB - on a client connecting, the line below fails + if (dynamic_pointer_cast(te) != NULL) + { + shared_ptr ste = dynamic_pointer_cast(te); + for (int i = 0; i < MAX_SIGN_LINES; i++) + { + ste->SetMessage(i,packet->lines[i]); + } + + app.DebugPrintf("verified = %d\tCensored = %d\n",packet->m_bVerified,packet->m_bCensored); + ste->SetVerified(packet->m_bVerified); + ste->SetCensored(packet->m_bCensored); + + ste->setChanged(); + } + else + { + app.DebugPrintf("dynamic_pointer_cast(te) == NULL\n"); + } + } + else + { + app.DebugPrintf("hasChunkAt failed\n"); + } +} + +void ClientConnection::handleTileEntityData(shared_ptr packet) +{ + if (minecraft->level->hasChunkAt(packet->x, packet->y, packet->z)) + { + shared_ptr te = minecraft->level->getTileEntity(packet->x, packet->y, packet->z); + + if (te != NULL) + { + if (packet->type == TileEntityDataPacket::TYPE_MOB_SPAWNER && dynamic_pointer_cast(te) != NULL) + { + dynamic_pointer_cast(te)->load(packet->tag); + } + //else if (packet.type == TileEntityDataPacket.TYPE_ADV_COMMAND && (te instanceof CommandBlockEntity)) + //{ + // ((CommandBlockEntity) te).load(packet.tag); + //} + //else if (packet.type == TileEntityDataPacket.TYPE_BEACON && (te instanceof BeaconTileEntity)) + //{ + // ((BeaconTileEntity) te).load(packet.tag); + //} + else if (packet->type == TileEntityDataPacket::TYPE_SKULL && dynamic_pointer_cast(te) != NULL) + { + dynamic_pointer_cast(te)->load(packet->tag); + } + } + } +} + +void ClientConnection::handleContainerSetData(shared_ptr packet) +{ + onUnhandledPacket(packet); + if (minecraft->localplayers[m_userIndex]->containerMenu != NULL && minecraft->localplayers[m_userIndex]->containerMenu->containerId == packet->containerId) + { + minecraft->localplayers[m_userIndex]->containerMenu->setData(packet->id, packet->value); + } +} + +void ClientConnection::handleSetEquippedItem(shared_ptr packet) +{ + shared_ptr entity = getEntity(packet->entity); + if (entity != NULL) + { + // 4J Stu - Brought forward change from 1.3 to fix #64688 - Customer Encountered: TU7: Content: Art: Aura of enchanted item is not displayed for other players in online game + entity->setEquippedSlot(packet->slot, packet->getItem() ); + } +} + +void ClientConnection::handleContainerClose(shared_ptr packet) +{ + minecraft->localplayers[m_userIndex]->closeContainer(); +} + +void ClientConnection::handleTileEvent(shared_ptr packet) +{ + PIXBeginNamedEvent(0,"Handle tile event\n"); + minecraft->level->tileEvent(packet->x, packet->y, packet->z, packet->tile, packet->b0, packet->b1); + PIXEndNamedEvent(); +} + +void ClientConnection::handleTileDestruction(shared_ptr packet) +{ + minecraft->level->destroyTileProgress(packet->getEntityId(), packet->getX(), packet->getY(), packet->getZ(), packet->getState()); +} + +bool ClientConnection::canHandleAsyncPackets() +{ + return minecraft != NULL && minecraft->level != NULL && minecraft->localplayers[m_userIndex] != NULL && level != NULL; +} + +void ClientConnection::handleGameEvent(shared_ptr gameEventPacket) +{ + int event = gameEventPacket->_event; + int param = gameEventPacket->param; + if (event >= 0 && event < GameEventPacket::EVENT_LANGUAGE_ID_LENGTH) + { + if (GameEventPacket::EVENT_LANGUAGE_ID[event] > 0) // 4J - was NULL check + { + minecraft->localplayers[m_userIndex]->displayClientMessage(GameEventPacket::EVENT_LANGUAGE_ID[event]); + } + } + if (event == GameEventPacket::START_RAINING) + { + level->getLevelData()->setRaining(true); + level->setRainLevel(1); + } + else if (event == GameEventPacket::STOP_RAINING) + { + level->getLevelData()->setRaining(false); + level->setRainLevel(0); + } + else if (event == GameEventPacket::CHANGE_GAME_MODE) + { + minecraft->localgameModes[m_userIndex]->setLocalMode(GameType::byId(param)); + } + else if (event == GameEventPacket::WIN_GAME) + { + ui.SetWinUserIndex( (BYTE)gameEventPacket->param ); + +#ifdef _XBOX + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // Hide the other players scenes + ui.ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), false); + + // This just allows it to be shown + if(minecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) minecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(false); + // Temporarily make this scene fullscreen + CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen ); + + app.CloseXuiScenesAndNavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_EndPoem); +#else + app.DebugPrintf("handleGameEvent packet for WIN_GAME - %d\n", m_userIndex); + // This just allows it to be shown + if(minecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) minecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(false); + ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_EndPoem, NULL, eUILayer_Scene, eUIGroup_Fullscreen); +#endif + } + else if( event == GameEventPacket::START_SAVING ) + { + if(!g_NetworkManager.IsHost()) + { + // Move app started to here so that it happens immediately otherwise back-to-back START/STOP packets + // leave the client stuck in the loading screen + app.SetGameStarted(false); + app.SetAction( ProfileManager.GetPrimaryPad(), eAppAction_RemoteServerSave ); + } + } + else if( event == GameEventPacket::STOP_SAVING ) + { + if(!g_NetworkManager.IsHost() ) app.SetGameStarted(true); + } +} + +void ClientConnection::handleComplexItemData(shared_ptr packet) +{ + if (packet->itemType == Item::map->id) + { + MapItem::getSavedData(packet->itemId, minecraft->level)->handleComplexItemData(packet->data); + } + else + { +// System.out.println("Unknown itemid: " + packet->itemId); // 4J removed + } +} + + + +void ClientConnection::handleLevelEvent(shared_ptr packet) +{ + switch(packet->type) + { + case LevelEvent::SOUND_DRAGON_DEATH: + { + Minecraft *pMinecraft = Minecraft::GetInstance(); + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if(pMinecraft->localplayers[i] != NULL && pMinecraft->localplayers[i]->level != NULL && pMinecraft->localplayers[i]->level->dimension->id == 1) + { + pMinecraft->localplayers[i]->awardStat(GenericStats::completeTheEnd(),GenericStats::param_noArgs()); + } + } + } + minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data); + + break; + default: + minecraft->level->levelEvent(packet->type, packet->x, packet->y, packet->z, packet->data); + break; + } +} + +void ClientConnection::handleAwardStat(shared_ptr packet) +{ + minecraft->localplayers[m_userIndex]->awardStatFromServer(GenericStats::stat(packet->statId), packet->getParamData()); +} + +void ClientConnection::handleUpdateMobEffect(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->entityId); + if (e == NULL || dynamic_pointer_cast(e) == NULL) return; + + ( dynamic_pointer_cast(e) )->addEffect(new MobEffectInstance(packet->effectId, packet->effectDurationTicks, packet->effectAmplifier)); +} + +void ClientConnection::handleRemoveMobEffect(shared_ptr packet) +{ + shared_ptr e = getEntity(packet->entityId); + if (e == NULL || dynamic_pointer_cast(e) == NULL) return; + + ( dynamic_pointer_cast(e) )->removeEffectNoUpdate(packet->effectId); +} + +bool ClientConnection::isServerPacketListener() +{ + return false; +} + +void ClientConnection::handlePlayerInfo(shared_ptr packet) +{ + unsigned int startingPrivileges = app.GetPlayerPrivileges(packet->m_networkSmallId); + + INetworkPlayer *networkPlayer = g_NetworkManager.GetPlayerBySmallId(packet->m_networkSmallId); + + if(networkPlayer != NULL && networkPlayer->IsHost()) + { + // Some settings should always be considered on for the host player + Player::enableAllPlayerPrivileges(startingPrivileges,true); + Player::setPlayerGamePrivilege(startingPrivileges,Player::ePlayerGamePrivilege_HOST,1); + } + + // 4J Stu - Repurposed this packet for player info that we want + app.UpdatePlayerInfo(packet->m_networkSmallId, packet->m_playerColourIndex, packet->m_playerPrivileges); + + shared_ptr entity = getEntity(packet->m_entityId); + if(entity != NULL && entity->GetType() == eTYPE_PLAYER) + { + shared_ptr player = dynamic_pointer_cast(entity); + player->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All, packet->m_playerPrivileges); + } + if(networkPlayer != NULL && networkPlayer->IsLocal()) + { + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + shared_ptr localPlayer = minecraft->localplayers[i]; + if(localPlayer != NULL && localPlayer->connection != NULL && localPlayer->connection->getNetworkPlayer() == networkPlayer ) + { + localPlayer->setPlayerGamePrivilege(Player::ePlayerGamePrivilege_All,packet->m_playerPrivileges); + displayPrivilegeChanges(localPlayer,startingPrivileges); + break; + } + } + } + + // 4J Stu - I don't think we care about this, so not converting it (came from 1.8.2) +#if 0 + PlayerInfo pi = playerInfoMap.get(packet.name); + if (pi == null && packet.add) { + pi = new PlayerInfo(packet.name); + playerInfoMap.put(packet.name, pi); + playerInfos.add(pi); + } + if (pi != null && !packet.add) { + playerInfoMap.remove(packet.name); + playerInfos.remove(pi); + } + if (packet.add && pi != null) { + pi.latency = packet.latency; + } +#endif +} + + +void ClientConnection::displayPrivilegeChanges(shared_ptr player, unsigned int oldPrivileges) +{ + int userIndex = player->GetXboxPad(); + unsigned int newPrivileges = player->getAllPlayerGamePrivileges(); + Player::EPlayerGamePrivileges priv = (Player::EPlayerGamePrivileges)0; + bool privOn = false; + for(unsigned int i = 0; i < Player::ePlayerGamePrivilege_MAX; ++i) + { + priv = (Player::EPlayerGamePrivileges) i; + if( Player::getPlayerGamePrivilege(newPrivileges,priv) != Player::getPlayerGamePrivilege(oldPrivileges,priv)) + { + privOn = Player::getPlayerGamePrivilege(newPrivileges,priv); + wstring message = L""; + if(app.GetGameHostOption(eGameHostOption_TrustPlayers) == 0) + { + switch(priv) + { + case Player::ePlayerGamePrivilege_CannotMine: + if(privOn) message = app.GetString(IDS_PRIV_MINE_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_MINE_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CannotBuild: + if(privOn) message = app.GetString(IDS_PRIV_BUILD_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_BUILD_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CanUseDoorsAndSwitches: + if(privOn) message = app.GetString(IDS_PRIV_USE_DOORS_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_USE_DOORS_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CanUseContainers: + if(privOn) message = app.GetString(IDS_PRIV_USE_CONTAINERS_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_USE_CONTAINERS_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CannotAttackAnimals: + if(privOn) message = app.GetString(IDS_PRIV_ATTACK_ANIMAL_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_ATTACK_ANIMAL_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CannotAttackMobs: + if(privOn) message = app.GetString(IDS_PRIV_ATTACK_MOB_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_ATTACK_MOB_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CannotAttackPlayers: + if(privOn) message = app.GetString(IDS_PRIV_ATTACK_PLAYER_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_ATTACK_PLAYER_TOGGLE_OFF); + break; + }; + } + switch(priv) + { + case Player::ePlayerGamePrivilege_Op: + if(privOn) message = app.GetString(IDS_PRIV_MODERATOR_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_MODERATOR_TOGGLE_OFF); + break; + }; + if(app.GetGameHostOption(eGameHostOption_CheatsEnabled) != 0) + { + switch(priv) + { + case Player::ePlayerGamePrivilege_CanFly: + if(privOn) message = app.GetString(IDS_PRIV_FLY_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_FLY_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_ClassicHunger: + if(privOn) message = app.GetString(IDS_PRIV_EXHAUSTION_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_EXHAUSTION_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_Invisible: + if(privOn) message = app.GetString(IDS_PRIV_INVISIBLE_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_INVISIBLE_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_Invulnerable: + if(privOn) message = app.GetString(IDS_PRIV_INVULNERABLE_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_INVULNERABLE_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CanToggleInvisible: + if(privOn) message = app.GetString(IDS_PRIV_CAN_INVISIBLE_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_CAN_INVISIBLE_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CanToggleFly: + if(privOn) message = app.GetString(IDS_PRIV_CAN_FLY_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_CAN_FLY_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CanToggleClassicHunger: + if(privOn) message = app.GetString(IDS_PRIV_CAN_EXHAUSTION_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_CAN_EXHAUSTION_TOGGLE_OFF); + break; + case Player::ePlayerGamePrivilege_CanTeleport: + if(privOn) message = app.GetString(IDS_PRIV_CAN_TELEPORT_TOGGLE_ON); + else message = app.GetString(IDS_PRIV_CAN_TELEPORT_TOGGLE_OFF); + break; + }; + } + if(!message.empty()) minecraft->gui->addMessage(message,userIndex); + } + } +} + +void ClientConnection::handleKeepAlive(shared_ptr packet) +{ + send(shared_ptr(new KeepAlivePacket(packet->id))); +} + +void ClientConnection::handlePlayerAbilities(shared_ptr playerAbilitiesPacket) +{ + shared_ptr player = minecraft->localplayers[m_userIndex]; + player->abilities.flying = playerAbilitiesPacket->isFlying(); + player->abilities.instabuild = playerAbilitiesPacket->canInstabuild(); + player->abilities.invulnerable = playerAbilitiesPacket->isInvulnerable(); + player->abilities.mayfly = playerAbilitiesPacket->canFly(); + player->abilities.setFlyingSpeed(playerAbilitiesPacket->getFlyingSpeed()); +} + +void ClientConnection::handleSoundEvent(shared_ptr packet) +{ + minecraft->level->playLocalSound(packet->getX(), packet->getY(), packet->getZ(), packet->getSound(), packet->getVolume(), packet->getPitch()); +} + +void ClientConnection::handleCustomPayload(shared_ptr customPayloadPacket) +{ + if (CustomPayloadPacket::TRADER_LIST_PACKET.compare(customPayloadPacket->identifier) == 0) + { + ByteArrayInputStream bais(customPayloadPacket->data); + DataInputStream input(&bais); + int containerId = input.readInt(); + if (ui.IsSceneInStack(m_userIndex, eUIScene_TradingMenu) && containerId == minecraft->localplayers[m_userIndex]->containerMenu->containerId) + { + shared_ptr trader = nullptr; + +#ifdef _XBOX + HXUIOBJ scene = app.GetCurrentScene(m_userIndex); + HXUICLASS thisClass = XuiFindClass( L"CXuiSceneTrading" ); + HXUICLASS objClass = XuiGetObjectClass( scene ); + + // Also returns TRUE if they are the same (which is what we want) + if( XuiClassDerivesFrom( objClass, thisClass ) ) + { + CXuiSceneTrading *screen; + HRESULT hr = XuiObjectFromHandle(scene, (void **) &screen); + if (FAILED(hr)) return; + trader = screen->getMerchant(); + } +#else + UIScene *scene = ui.GetTopScene(m_userIndex, eUILayer_Scene); + UIScene_TradingMenu *screen = (UIScene_TradingMenu *)scene; + trader = screen->getMerchant(); +#endif + + MerchantRecipeList *recipeList = MerchantRecipeList::createFromStream(&input); + trader->overrideOffers(recipeList); + } + } +} + +Connection *ClientConnection::getConnection() +{ + return connection; +} + +// 4J Added +void ClientConnection::handleServerSettingsChanged(shared_ptr packet) +{ + if(packet->action==ServerSettingsChangedPacket::HOST_IN_GAME_SETTINGS) + { + app.SetGameHostOption(eGameHostOption_All, packet->data); + } + else if(packet->action==ServerSettingsChangedPacket::HOST_DIFFICULTY) + { + for(unsigned int i = 0; i < minecraft->levels.length; ++i) + { + if( minecraft->levels[i] != NULL ) + { + app.DebugPrintf("ClientConnection::handleServerSettingsChanged - Difficulty = %d",packet->data); + minecraft->levels[i]->difficulty = packet->data; + } + } + } + else + { + //options + //minecraft->options->SetGamertagSetting((packet->data==0)?false:true); + app.SetGameHostOption(eGameHostOption_Gamertags, packet->data); + } + +} + +void ClientConnection::handleXZ(shared_ptr packet) +{ + if(packet->action==XZPacket::STRONGHOLD) + { + minecraft->levels[0]->getLevelData()->setXStronghold(packet->x); + minecraft->levels[0]->getLevelData()->setZStronghold(packet->z); + minecraft->levels[0]->getLevelData()->setHasStronghold(); + } +} + +void ClientConnection::handleUpdateProgress(shared_ptr packet) +{ + if(!g_NetworkManager.IsHost() ) Minecraft::GetInstance()->progressRenderer->progressStagePercentage( packet->m_percentage ); +} + +void ClientConnection::handleUpdateGameRuleProgressPacket(shared_ptr packet) +{ + LPCWSTR string = app.GetGameRulesString(packet->m_messageId); + if(string != NULL) + { + wstring message(string); + message = GameRuleDefinition::generateDescriptionString(packet->m_definitionType,message,packet->m_data.data,packet->m_data.length); + if(minecraft->localgameModes[m_userIndex]!=NULL) + { + minecraft->localgameModes[m_userIndex]->getTutorial()->setMessage(message, packet->m_icon, packet->m_auxValue); + } + } + // If this rule has a data tag associated with it, then we save that in user profile data + if(packet->m_dataTag > 0 && packet->m_dataTag <= 32) + { + app.DebugPrintf("handleUpdateGameRuleProgressPacket: Data tag is in range, so updating profile data\n"); + app.SetSpecialTutorialCompletionFlag(m_userIndex, packet->m_dataTag - 1); + } + delete [] packet->m_data.data; +} + +// 4J Stu - TU-1 hotfix +// Fix for #13191 - The host of a game can get a message informing them that the connection to the server has been lost +int ClientConnection::HostDisconnectReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // 4J-PB - if they have a trial texture pack, they don't get to save the world + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + DLCPack *pDLCPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack(); + if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + // no upsell, we're about to quit + MinecraftServer::getInstance()->setSaveOnExit( false ); + // flag a app action of exit game + app.SetAction(iPad,eAppAction_ExitWorld); + } + } + +#if defined(_XBOX_ONE) || defined(__ORBIS__) + // Give the player the option to save their game + // does the save exist? + bool bSaveExists; + StorageManager.DoesSaveExist(&bSaveExists); + // 4J-PB - we check if the save exists inside the libs + // we need to ask if they are sure they want to overwrite the existing game + if(bSaveExists && StorageManager.GetSaveDisabled()) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&ClientConnection::ExitGameAndSaveReturned,NULL, app.GetStringTable()); + } + else +#else + // Give the player the option to save their game + // does the save exist? + bool bSaveExists; + StorageManager.DoesSaveExist(&bSaveExists); + // 4J-PB - we check if the save exists inside the libs + // we need to ask if they are sure they want to overwrite the existing game + if(bSaveExists) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&ClientConnection::ExitGameAndSaveReturned,NULL, app.GetStringTable()); + } + else +#endif + { +#if defined(_XBOX_ONE) || defined(__ORBIS__) + StorageManager.SetSaveDisabled(false); +#endif + MinecraftServer::getInstance()->setSaveOnExit( true ); + // flag a app action of exit game + app.SetAction(iPad,eAppAction_ExitWorld); + } + + return 0; +} + +int ClientConnection::ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + //INT saveOrCheckpointId = 0; + //bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); + //SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId); +#if defined(_XBOX_ONE) || defined(__ORBIS__) + StorageManager.SetSaveDisabled(false); +#endif + MinecraftServer::getInstance()->setSaveOnExit( true ); + } + else + { + MinecraftServer::getInstance()->setSaveOnExit( false ); + } + // flag a app action of exit game + app.SetAction(iPad,eAppAction_ExitWorld); + return 0; +} + +// +wstring ClientConnection::GetDisplayNameByGamertag(wstring gamertag) +{ +#ifdef _DURANGO + wstring displayName = g_NetworkManager.GetDisplayNameByGamertag(gamertag); + return displayName; +#else + return gamertag; +#endif +} diff --git a/Minecraft.Client/ClientConnection.h b/Minecraft.Client/ClientConnection.h new file mode 100644 index 0000000..2ce46ce --- /dev/null +++ b/Minecraft.Client/ClientConnection.h @@ -0,0 +1,140 @@ +#pragma once +#include "..\Minecraft.World\net.minecraft.network.h" +class Minecraft; +class MultiPlayerLevel; +class SavedDataStorage; +class Socket; +class MultiplayerLocalPlayer; + +class ClientConnection : public PacketListener +{ +private: + enum eClientConnectionConnectingState + { + eCCPreLoginSent = 0, + eCCPreLoginReceived, + eCCLoginSent, + eCCLoginReceived, + eCCConnected + }; +private: + bool done; + Connection *connection; +public: + wstring message; + bool createdOk; // 4J added +private: + Minecraft *minecraft; + MultiPlayerLevel *level; + bool started; + + // 4J Stu - I don't think we are interested in the PlayerInfo data, so I'm not going to use it at the moment + //Map playerInfoMap = new HashMap(); +public: + //List playerInfos = new ArrayList(); + + int maxPlayers; + +public: + bool isStarted() { return started; } // 4J Added + bool isClosed() { return done; } // 4J Added + Socket *getSocket() { return connection->getSocket(); } // 4J Added + +private: + DWORD m_userIndex; // 4J Added +public: + SavedDataStorage *savedDataStorage; + ClientConnection(Minecraft *minecraft, const wstring& ip, int port); + ClientConnection(Minecraft *minecraft, Socket *socket, int iUserIndex = -1); + ~ClientConnection(); + void tick(); + INetworkPlayer *getNetworkPlayer(); + virtual void handleLogin(shared_ptr packet); + virtual void handleAddEntity(shared_ptr packet); + virtual void handleAddExperienceOrb(shared_ptr packet); + virtual void handleAddGlobalEntity(shared_ptr packet); + virtual void handleAddPainting(shared_ptr packet); + virtual void handleSetEntityMotion(shared_ptr packet); + virtual void handleSetEntityData(shared_ptr packet); + virtual void handleAddPlayer(shared_ptr packet); + virtual void handleTeleportEntity(shared_ptr packet); + virtual void handleMoveEntity(shared_ptr packet); + virtual void handleRotateMob(shared_ptr packet); + virtual void handleMoveEntitySmall(shared_ptr packet); + virtual void handleRemoveEntity(shared_ptr packet); + virtual void handleMovePlayer(shared_ptr packet); + + Random *random; + + // 4J Added + virtual void handleChunkVisibilityArea(shared_ptr packet); + + virtual void handleChunkVisibility(shared_ptr packet); + virtual void handleChunkTilesUpdate(shared_ptr packet); + virtual void handleBlockRegionUpdate(shared_ptr packet); + virtual void handleTileUpdate(shared_ptr packet); + virtual void handleDisconnect(shared_ptr packet); + virtual void onDisconnect(DisconnectPacket::eDisconnectReason reason, void *reasonObjects); + void sendAndDisconnect(shared_ptr packet); + void send(shared_ptr packet); + virtual void handleTakeItemEntity(shared_ptr packet); + virtual void handleChat(shared_ptr packet); + virtual void handleAnimate(shared_ptr packet); + virtual void handleEntityActionAtPosition(shared_ptr packet); + virtual void handlePreLogin(shared_ptr packet); + void close(); + virtual void handleAddMob(shared_ptr packet); + virtual void handleSetTime(shared_ptr packet); + virtual void handleSetSpawn(shared_ptr packet); + virtual void handleRidePacket(shared_ptr packet); + virtual void handleEntityEvent(shared_ptr packet); +private: + shared_ptr getEntity(int entityId); + wstring GetDisplayNameByGamertag(wstring gamertag); +public: + virtual void handleSetHealth(shared_ptr packet); + virtual void handleSetExperience(shared_ptr packet); + virtual void handleRespawn(shared_ptr packet); + virtual void handleExplosion(shared_ptr packet); + virtual void handleContainerOpen(shared_ptr packet); + virtual void handleContainerSetSlot(shared_ptr packet); + virtual void handleContainerAck(shared_ptr packet); + virtual void handleContainerContent(shared_ptr packet); + virtual void handleSignUpdate(shared_ptr packet); + virtual void handleTileEntityData(shared_ptr packet); + virtual void handleContainerSetData(shared_ptr packet); + virtual void handleSetEquippedItem(shared_ptr packet); + virtual void handleContainerClose(shared_ptr packet); + virtual void handleTileEvent(shared_ptr packet); + virtual void handleTileDestruction(shared_ptr packet); + virtual bool canHandleAsyncPackets(); + virtual void handleGameEvent(shared_ptr gameEventPacket); + virtual void handleComplexItemData(shared_ptr packet); + virtual void handleLevelEvent(shared_ptr packet); + virtual void handleAwardStat(shared_ptr packet); + virtual void handleUpdateMobEffect(shared_ptr packet); + virtual void handleRemoveMobEffect(shared_ptr packet); + virtual bool isServerPacketListener(); + virtual void handlePlayerInfo(shared_ptr packet); + virtual void handleKeepAlive(shared_ptr packet); + virtual void handlePlayerAbilities(shared_ptr playerAbilitiesPacket); + virtual void handleSoundEvent(shared_ptr packet); + virtual void handleCustomPayload(shared_ptr customPayloadPacket); + virtual Connection *getConnection(); + + // 4J Added + virtual void handleServerSettingsChanged(shared_ptr packet); + virtual void handleTexture(shared_ptr packet); + virtual void handleTextureAndGeometry(shared_ptr packet); + virtual void handleUpdateProgress(shared_ptr packet); + + // 4J Added + static int HostDisconnectReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitGameAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + virtual void handleTextureChange(shared_ptr packet); + virtual void handleTextureAndGeometryChange(shared_ptr packet); + virtual void handleUpdateGameRuleProgressPacket(shared_ptr packet); + virtual void handleXZ(shared_ptr packet); + + void displayPrivilegeChanges(shared_ptr player, unsigned int oldPrivileges); +}; \ No newline at end of file diff --git a/Minecraft.Client/ClientConstants.cpp b/Minecraft.Client/ClientConstants.cpp new file mode 100644 index 0000000..1e4cead --- /dev/null +++ b/Minecraft.Client/ClientConstants.cpp @@ -0,0 +1,5 @@ +#include "stdafx.h" +#include "ClientConstants.h" + +const wstring ClientConstants::VERSION_STRING = wstring(L"Minecraft Xbox ") + VER_FILEVERSION_STR_W;//+ SharedConstants::VERSION_STRING; +bool ClientConstants::SHOW_LCEMP_WATERMARK = true; \ No newline at end of file diff --git a/Minecraft.Client/ClientConstants.h b/Minecraft.Client/ClientConstants.h new file mode 100644 index 0000000..28d16aa --- /dev/null +++ b/Minecraft.Client/ClientConstants.h @@ -0,0 +1,19 @@ +#pragma once +using namespace std; + +class ClientConstants +{ + + // This file holds global constants used by the client. + // The file should be replaced at compile-time with the + // proper settings for the given compilation. For example, + // release builds should replace this file with no-cheat + // settings. + + // INTERNAL DEVELOPMENT SETTINGS +public: + static const wstring VERSION_STRING; + + static const bool DEADMAU5_CAMERA_CHEATS = false; + static bool SHOW_LCEMP_WATERMARK; +}; \ No newline at end of file diff --git a/Minecraft.Client/ClockTexture.cpp b/Minecraft.Client/ClockTexture.cpp new file mode 100644 index 0000000..d8abb78 --- /dev/null +++ b/Minecraft.Client/ClockTexture.cpp @@ -0,0 +1,119 @@ +#include "stdafx.h" +#include "Minecraft.h" +#include "..\Minecraft.World\net.minecraft.world.level.h" +#include "..\Minecraft.World\net.minecraft.world.level.dimension.h" +#include "MultiplayerLocalPlayer.h" +#include "..\Minecraft.World\JavaMath.h" +#include "Texture.h" +#include "ClockTexture.h" + +ClockTexture::ClockTexture() : StitchedTexture(L"compass") +{ + rot = rota = 0.0; + m_dataTexture = NULL; + m_iPad = XUSER_INDEX_ANY; +} + +ClockTexture::ClockTexture(int iPad, ClockTexture *dataTexture) : StitchedTexture(L"compass") +{ + rot = rota = 0.0; + m_dataTexture = dataTexture; + m_iPad = iPad; +} + +void ClockTexture::cycleFrames() +{ + + Minecraft *mc = Minecraft::GetInstance(); + + double rott = 0; + if (m_iPad >= 0 && m_iPad < XUSER_MAX_COUNT && mc->level != NULL && mc->localplayers[m_iPad] != NULL) + { + float time = mc->localplayers[m_iPad]->level->getTimeOfDay(1); + rott = time; + if (!mc->localplayers[m_iPad]->level->dimension->isNaturalDimension()) + { + rott = Math::random(); + } + } + else + { + // 4J Stu - For the static version, pretend we are already on a frame other than 0 + frame = 1; + } + + double rotd = rott - rot; + while (rotd < -.5) + rotd += 1.0; + while (rotd >= .5) + rotd -= 1.0; + if (rotd < -1) rotd = -1; + if (rotd > 1) rotd = 1; + rota += rotd * 0.1; + rota *= 0.8; + + rot += rota; + + // 4J Stu - We share data with another texture + if(m_dataTexture != NULL) + { + int newFrame = (int) ((rot + 1.0) * m_dataTexture->frames->size()) % m_dataTexture->frames->size(); + while (newFrame < 0) + { + newFrame = (newFrame + m_dataTexture->frames->size()) % m_dataTexture->frames->size(); + } + if (newFrame != frame) + { + frame = newFrame; + m_dataTexture->source->blit(x, y, m_dataTexture->frames->at(this->frame), rotated); + } + } + else + { + int newFrame = (int) ((rot + 1.0) * frames->size()) % frames->size(); + while (newFrame < 0) + { + newFrame = (newFrame + frames->size()) % frames->size(); + } + if (newFrame != frame) + { + frame = newFrame; + source->blit(x, y, frames->at(this->frame), rotated); + } + } +} + +int ClockTexture::getSourceWidth() const +{ + return source->getWidth(); +} + +int ClockTexture::getSourceHeight() const +{ + return source->getHeight(); +} + +int ClockTexture::getFrames() +{ + if(m_dataTexture == NULL) + { + return StitchedTexture::getFrames(); + } + else + { + return m_dataTexture->getFrames(); + } +} + +void ClockTexture::freeFrameTextures() +{ + if(m_dataTexture == NULL) + { + StitchedTexture::freeFrameTextures(); + } +} + +bool ClockTexture::hasOwnData() +{ + return m_dataTexture == NULL; +} \ No newline at end of file diff --git a/Minecraft.Client/ClockTexture.h b/Minecraft.Client/ClockTexture.h new file mode 100644 index 0000000..e042887 --- /dev/null +++ b/Minecraft.Client/ClockTexture.h @@ -0,0 +1,21 @@ +#pragma once +#include "StitchedTexture.h" + +class ClockTexture : public StitchedTexture +{ +private: + double rot, rota; + int m_iPad; + ClockTexture* m_dataTexture; + +public: + ClockTexture(); + ClockTexture(int iPad, ClockTexture *dataTexture); + void cycleFrames(); + + virtual int getSourceWidth() const; + virtual int getSourceHeight() const; + virtual int getFrames(); + virtual void freeFrameTextures(); // 4J added + virtual bool hasOwnData(); // 4J Added +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/App_Defines.h b/Minecraft.Client/Common/App_Defines.h new file mode 100644 index 0000000..de1d1bd --- /dev/null +++ b/Minecraft.Client/Common/App_Defines.h @@ -0,0 +1,130 @@ +#pragma once + + +// 4J Stu - For non-splitscreen menus, default to this screen +#define DEFAULT_XUI_MENU_USER 0 +#define MULTITHREAD_ENABLE +#define MAX_CAPENAME_SIZE 32 +#define MAX_BANNERNAME_SIZE 32 +#define MAX_TMSFILENAME_SIZE 40 +#define MAX_TYPE_SIZE 32 +#define MAX_EXTENSION_TYPES 3 + +#ifdef __PSVITA__ +#define MAX_LOCAL_PLAYERS 1 +#else +#define MAX_LOCAL_PLAYERS 4 +#endif + +// 4J Stu - Required for sentient reporting of whether the volume level has been changed or not +#define DEFAULT_VOLUME_LEVEL 100 + +#define GAME_HOST_OPTION_BITMASK_DIFFICULTY 0x00000003 // 0 - 3 +#define GAME_HOST_OPTION_BITMASK_FRIENDSOFFRIENDS 0x00000004 +#define GAME_HOST_OPTION_BITMASK_GAMERTAGS 0x00000008 +#define GAME_HOST_OPTION_BITMASK_GAMETYPE 0x00000030 +#define GAME_HOST_OPTION_BITMASK_LEVELTYPE 0x00000040 +#define GAME_HOST_OPTION_BITMASK_STRUCTURES 0x00000080 +#define GAME_HOST_OPTION_BITMASK_BONUSCHEST 0x00000100 +#define GAME_HOST_OPTION_BITMASK_BEENINCREATIVE 0x00000200 +#define GAME_HOST_OPTION_BITMASK_PVP 0x00000400 +#define GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS 0x00000800 +#define GAME_HOST_OPTION_BITMASK_TNT 0x00001000 +#define GAME_HOST_OPTION_BITMASK_FIRESPREADS 0x00002000 +#define GAME_HOST_OPTION_BITMASK_HOSTFLY 0x00004000 +#define GAME_HOST_OPTION_BITMASK_HOSTHUNGER 0x00008000 +#define GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE 0x00010000 +#define GAME_HOST_OPTION_BITMASK_BEDROCKFOG 0x00020000 +#define GAME_HOST_OPTION_BITMASK_DISABLESAVE 0x00040000 +#define GAME_HOST_OPTION_BITMASK_ALL 0xFFFFFFFF + +#ifdef _XBOX +#define PROFILE_VERSION_1 1 +#define PROFILE_VERSION_2 2 +#define PROFILE_VERSION_3 3 +#define PROFILE_VERSION_4 4 +#define PROFILE_VERSION_5 6 +#define PROFILE_VERSION_6 7 +#define PROFILE_VERSION_7 8 +#endif +#define PROFILE_VERSION_8 10 +#define PROFILE_VERSION_9 11 + +#define PROFILE_VERSION_10 12 + +// 4J-JEV: New Statistics and Achievements for 'NexGen' platforms. +#define PROFILE_VERSION_BUILD_JUNE14 13 + +#define MAX_FAVORITE_SKINS 10 // these are stored in the profile data so keep it small + + + + + +// defines for game settings - uiBitmaskValues + +#define GAMESETTING_CLOUDS 0x00000001 +#define GAMESETTING_ONLINE 0x00000002 +#define GAMESETTING_INVITEONLY 0x00000004 +#define GAMESETTING_FRIENDSOFFRIENDS 0x00000008 +#define GAMESETTING_DISPLAYUPDATEMSG 0x00000030 +#define GAMESETTING_BEDROCKFOG 0x00000040 +#define GAMESETTING_DISPLAYHUD 0x00000080 +#define GAMESETTING_DISPLAYHAND 0x00000100 +#define GAMESETTING_CUSTOMSKINANIM 0x00000200 +#define GAMESETTING_DEATHMESSAGES 0x00000400 +#define GAMESETTING_UISIZE 0x00001800 +#define GAMESETTING_UISIZE_SPLITSCREEN 0x00006000 +#define GAMESETTING_ANIMATEDCHARACTER 0x00008000 +#define GAMESETTING_PS3EULAREAD 0x00010000 +#define GAMESETTING_PSVITANETWORKMODEADHOC 0x00020000 + + +// defines for languages + +#define MINECRAFT_LANGUAGE_DEFAULT 0x00 +#define MINECRAFT_LANGUAGE_ENGLISH 0x01 +#define MINECRAFT_LANGUAGE_JAPANESE 0x02 +#define MINECRAFT_LANGUAGE_GERMAN 0x03 +#define MINECRAFT_LANGUAGE_FRENCH 0x04 +#define MINECRAFT_LANGUAGE_SPANISH 0x05 +#define MINECRAFT_LANGUAGE_ITALIAN 0x06 +#define MINECRAFT_LANGUAGE_KOREAN 0x07 +#define MINECRAFT_LANGUAGE_TCHINESE 0x08 +#define MINECRAFT_LANGUAGE_PORTUGUESE 0x09 +#define MINECRAFT_LANGUAGE_BRAZILIAN 0x0A +#define MINECRAFT_LANGUAGE_RUSSIAN 0x0B +#define MINECRAFT_LANGUAGE_DUTCH 0x0C +#define MINECRAFT_LANGUAGE_FINISH 0x0D +#define MINECRAFT_LANGUAGE_SWEDISH 0x0E +#define MINECRAFT_LANGUAGE_DANISH 0x0F +#define MINECRAFT_LANGUAGE_NORWEGIAN 0x10 +#define MINECRAFT_LANGUAGE_POLISH 0x11 +#define MINECRAFT_LANGUAGE_TURKISH 0x12 +#define MINECRAFT_LANGUAGE_LATINAMERICANSPANISH 0x13 +#define MINECRAFT_LANGUAGE_GREEK 0x14 + + + /* Match these + + const int XC_LANGUAGE_ENGLISH =1; + const int XC_LANGUAGE_JAPANESE =2; + const int XC_LANGUAGE_GERMAN =3; + const int XC_LANGUAGE_FRENCH =4; + const int XC_LANGUAGE_SPANISH =5; + const int XC_LANGUAGE_ITALIAN =6; + const int XC_LANGUAGE_KOREAN =7; + const int XC_LANGUAGE_TCHINESE =8; + const int XC_LANGUAGE_PORTUGUESE =9; + const int XC_LANGUAGE_BRAZILIAN =10; + const int XC_LANGUAGE_RUSSIAN =11; + const int XC_LANGUAGE_DUTCH =12; + const int XC_LANGUAGE_FINISH =13; + const int XC_LANGUAGE_SWEDISH =14; + const int XC_LANGUAGE_DANISH =15; + const int XC_LANGUAGE_NORWEGIAN =16; + const int XC_LANGUAGE_POLISH =17; + const int XC_LANGUAGE_TURKISH =18; + const int XC_LANGUAGE_LATINAMERICANSPANISH =19; + const int XC_LANGUAGE_GREEK =20; + */ diff --git a/Minecraft.Client/Common/App_enums.h b/Minecraft.Client/Common/App_enums.h new file mode 100644 index 0000000..b6c484d --- /dev/null +++ b/Minecraft.Client/Common/App_enums.h @@ -0,0 +1,913 @@ +#pragma once + +enum eFileExtensionType +{ + eFileExtensionType_PNG=0, + eFileExtensionType_INF, + eFileExtensionType_DAT, +}; + +enum eTMSFileType +{ + eTMSFileType_MinecraftStore=0, + eTMSFileType_TexturePack, + eTMSFileType_All +}; + +enum eTPDFileType +{ + eTPDFileType_Loc=0, + eTPDFileType_Icon, +// eTPDFileType_Banner, + eTPDFileType_Comparison, +}; + +enum eFont +{ + eFont_European=0, + eFont_Korean, + eFont_Japanese, + eFont_Chinese, + eFont_None, // to fallback to nothing +}; + +enum eXuiAction +{ + eAppAction_Idle=0, + eAppAction_SaveGame, + eAppAction_SaveGameCapturedThumbnail, + eAppAction_ExitWorld, + eAppAction_ExitWorldCapturedThumbnail, + eAppAction_ExitWorldTrial, + //eAppAction_ExitGameFatalLoadError, + eAppAction_Respawn, + eAppAction_WaitForRespawnComplete, + eAppAction_PrimaryPlayerSignedOut, + eAppAction_PrimaryPlayerSignedOutReturned, + eAppAction_PrimaryPlayerSignedOutReturned_Menus, + eAppAction_ExitPlayer, // secondary player + eAppAction_ExitPlayerPreLogin, + eAppAction_TrialOver, + eAppAction_ExitTrial, + eAppAction_WaitForDimensionChangeComplete, + eAppAction_SocialPost, + eAppAction_SocialPostScreenshot, + eAppAction_EthernetDisconnected, + eAppAction_EthernetDisconnectedReturned, + eAppAction_EthernetDisconnectedReturned_Menus, + eAppAction_ExitAndJoinFromInvite, + eAppAction_DashboardTrialJoinFromInvite, + eAppAction_ExitAndJoinFromInviteConfirmed, + eAppAction_JoinFromInvite, + eAppAction_ChangeSessionType, + eAppAction_SetDefaultOptions, + eAppAction_LocalPlayerJoined, + eAppAction_RemoteServerSave, + eAppAction_WaitRemoteServerSaveComplete, + eAppAction_FailedToJoinNoPrivileges, + eAppAction_AutosaveSaveGame, + eAppAction_AutosaveSaveGameCapturedThumbnail, + eAppAction_ProfileReadError, + eAppAction_DisplayLavaMessage, + eAppAction_BanLevel, + eAppAction_LevelInBanLevelList, + + eAppAction_ReloadTexturePack, + eAppAction_TexturePackRequired, // when the user has joined from invite, but doesn't have the texture pack + +#ifdef __ORBIS__ + eAppAction_OptionsSaveNoSpace, +#endif + eAppAction_DebugText, + +}; + + + +enum eTMSAction +{ + eTMSAction_Idle=0, + eTMSAction_TMS_RetrieveFiles_Complete, + eTMSAction_TMSPP_RetrieveFiles_CreateLoad_SignInReturned, + eTMSAction_TMSPP_RetrieveFiles_RunPlayGame, + eTMSAction_TMSPP_RetrieveFiles_HelpAndOptions, + eTMSAction_TMSPP_RetrieveFiles_DLCMain, + eTMSAction_TMSPP_GlobalFileList, + eTMSAction_TMSPP_GlobalFileList_Waiting, +// eTMSAction_TMSPP_ConfigFile, +// eTMSAction_TMSPP_ConfigFile_Waiting, + eTMSAction_TMSPP_UserFileList, + eTMSAction_TMSPP_UserFileList_Waiting, + eTMSAction_TMSPP_XUIDSFile, + eTMSAction_TMSPP_XUIDSFile_Waiting, + eTMSAction_TMSPP_DLCFile, + eTMSAction_TMSPP_DLCFile_Waiting, + eTMSAction_TMSPP_BannedListFile, + eTMSAction_TMSPP_BannedListFile_Waiting, + eTMSAction_TMSPP_RetrieveFiles_Complete, + eTMSAction_TMSPP_DLCFileOnly, + eTMSAction_TMSPP_RetrieveUserFilelist_DLCFileOnly, +}; + +// The server runs on its own thread, so we need to call its actions there rather than where all other Xui actions are performed +// In general these are debugging options +enum eXuiServerAction +{ + eXuiServerAction_Idle=0, + eXuiServerAction_DropItem, // Debug + eXuiServerAction_SaveGame, + eXuiServerAction_AutoSaveGame, + eXuiServerAction_SpawnMob, // Debug + eXuiServerAction_PauseServer, + eXuiServerAction_ToggleRain, // Debug + eXuiServerAction_ToggleThunder, // Debug + eXuiServerAction_ServerSettingChanged_Gamertags, + eXuiServerAction_ServerSettingChanged_Difficulty, + eXuiServerAction_ExportSchematic, //Debug + eXuiServerAction_ServerSettingChanged_BedrockFog, + eXuiServerAction_SetCameraLocation, //Debug +}; + +enum eGameSetting +{ + eGameSetting_MusicVolume=0, + eGameSetting_SoundFXVolume, + eGameSetting_Gamma, + eGameSetting_Difficulty, + eGameSetting_Sensitivity_InGame, + eGameSetting_Sensitivity_InMenu, + eGameSetting_ViewBob, + eGameSetting_ControlScheme, + eGameSetting_ControlInvertLook, + eGameSetting_ControlSouthPaw, + eGameSetting_SplitScreenVertical, + eGameSetting_GamertagsVisible, + // Interim TU 1.6.6 + eGameSetting_Autosave, + eGameSetting_DisplaySplitscreenGamertags, + eGameSetting_Hints, + eGameSetting_InterfaceOpacity, + eGameSetting_Tooltips, + // TU5 + eGameSetting_Clouds, + eGameSetting_Online, + eGameSetting_InviteOnly, + eGameSetting_FriendsOfFriends, + eGameSetting_DisplayUpdateMessage, + + // TU6 + eGameSetting_BedrockFog, + eGameSetting_DisplayHUD, + eGameSetting_DisplayHand, + + // TU7 + eGameSetting_CustomSkinAnim, + + // TU9 + eGameSetting_DeathMessages, + eGameSetting_UISize, + eGameSetting_UISizeSplitscreen, + eGameSetting_AnimatedCharacter, + + // PS3 + eGameSetting_PS3_EULA_Read, + + // PSVita + eGameSetting_PSVita_NetworkModeAdhoc, + + +}; + + + +enum eGameMode +{ + eMode_Singleplayer, + eMode_Multiplayer +}; + + +enum eMinecraftColour +{ + eMinecraftColour_NOT_SET, + + eMinecraftColour_Foliage_Evergreen, + eMinecraftColour_Foliage_Birch, + eMinecraftColour_Foliage_Default, + eMinecraftColour_Foliage_Common, + eMinecraftColour_Foliage_Ocean, + eMinecraftColour_Foliage_Plains, + eMinecraftColour_Foliage_Desert, + eMinecraftColour_Foliage_ExtremeHills, + eMinecraftColour_Foliage_Forest, + eMinecraftColour_Foliage_Taiga, + eMinecraftColour_Foliage_Swampland, + eMinecraftColour_Foliage_River, + eMinecraftColour_Foliage_Hell, + eMinecraftColour_Foliage_Sky, + eMinecraftColour_Foliage_FrozenOcean, + eMinecraftColour_Foliage_FrozenRiver, + eMinecraftColour_Foliage_IcePlains, + eMinecraftColour_Foliage_IceMountains, + eMinecraftColour_Foliage_MushroomIsland, + eMinecraftColour_Foliage_MushroomIslandShore, + eMinecraftColour_Foliage_Beach, + eMinecraftColour_Foliage_DesertHills, + eMinecraftColour_Foliage_ForestHills, + eMinecraftColour_Foliage_TaigaHills, + eMinecraftColour_Foliage_ExtremeHillsEdge, + eMinecraftColour_Foliage_Jungle, + eMinecraftColour_Foliage_JungleHills, + + eMinecraftColour_Grass_Common, + eMinecraftColour_Grass_Ocean, + eMinecraftColour_Grass_Plains, + eMinecraftColour_Grass_Desert, + eMinecraftColour_Grass_ExtremeHills, + eMinecraftColour_Grass_Forest, + eMinecraftColour_Grass_Taiga, + eMinecraftColour_Grass_Swampland, + eMinecraftColour_Grass_River, + eMinecraftColour_Grass_Hell, + eMinecraftColour_Grass_Sky, + eMinecraftColour_Grass_FrozenOcean, + eMinecraftColour_Grass_FrozenRiver, + eMinecraftColour_Grass_IcePlains, + eMinecraftColour_Grass_IceMountains, + eMinecraftColour_Grass_MushroomIsland, + eMinecraftColour_Grass_MushroomIslandShore, + eMinecraftColour_Grass_Beach, + eMinecraftColour_Grass_DesertHills, + eMinecraftColour_Grass_ForestHills, + eMinecraftColour_Grass_TaigaHills, + eMinecraftColour_Grass_ExtremeHillsEdge, + eMinecraftColour_Grass_Jungle, + eMinecraftColour_Grass_JungleHills, + + eMinecraftColour_Water_Ocean, + eMinecraftColour_Water_Plains, + eMinecraftColour_Water_Desert, + eMinecraftColour_Water_ExtremeHills, + eMinecraftColour_Water_Forest, + eMinecraftColour_Water_Taiga, + eMinecraftColour_Water_Swampland, + eMinecraftColour_Water_River, + eMinecraftColour_Water_Hell, + eMinecraftColour_Water_Sky, + eMinecraftColour_Water_FrozenOcean, + eMinecraftColour_Water_FrozenRiver, + eMinecraftColour_Water_IcePlains, + eMinecraftColour_Water_IceMountains, + eMinecraftColour_Water_MushroomIsland, + eMinecraftColour_Water_MushroomIslandShore, + eMinecraftColour_Water_Beach, + eMinecraftColour_Water_DesertHills, + eMinecraftColour_Water_ForestHills, + eMinecraftColour_Water_TaigaHills, + eMinecraftColour_Water_ExtremeHillsEdge, + eMinecraftColour_Water_Jungle, + eMinecraftColour_Water_JungleHills, + + eMinecraftColour_Sky_Ocean, + eMinecraftColour_Sky_Plains, + eMinecraftColour_Sky_Desert, + eMinecraftColour_Sky_ExtremeHills, + eMinecraftColour_Sky_Forest, + eMinecraftColour_Sky_Taiga, + eMinecraftColour_Sky_Swampland, + eMinecraftColour_Sky_River, + eMinecraftColour_Sky_Hell, + eMinecraftColour_Sky_Sky, + eMinecraftColour_Sky_FrozenOcean, + eMinecraftColour_Sky_FrozenRiver, + eMinecraftColour_Sky_IcePlains, + eMinecraftColour_Sky_IceMountains, + eMinecraftColour_Sky_MushroomIsland, + eMinecraftColour_Sky_MushroomIslandShore, + eMinecraftColour_Sky_Beach, + eMinecraftColour_Sky_DesertHills, + eMinecraftColour_Sky_ForestHills, + eMinecraftColour_Sky_TaigaHills, + eMinecraftColour_Sky_ExtremeHillsEdge, + eMinecraftColour_Sky_Jungle, + eMinecraftColour_Sky_JungleHills, + + eMinecraftColour_Tile_RedstoneDust, + eMinecraftColour_Tile_RedstoneDustUnlit, + eMinecraftColour_Tile_RedstoneDustLitMin, + eMinecraftColour_Tile_RedstoneDustLitMax, + eMinecraftColour_Tile_StemMin, + eMinecraftColour_Tile_StemMax, + eMinecraftColour_Tile_WaterLily, + + eMinecraftColour_Sky_Dawn_Dark, + eMinecraftColour_Sky_Dawn_Bright, + + eMinecraftColour_Material_None, + eMinecraftColour_Material_Grass, + eMinecraftColour_Material_Sand, + eMinecraftColour_Material_Cloth, + eMinecraftColour_Material_Fire, + eMinecraftColour_Material_Ice, + eMinecraftColour_Material_Metal, + eMinecraftColour_Material_Plant, + eMinecraftColour_Material_Snow, + eMinecraftColour_Material_Clay, + eMinecraftColour_Material_Dirt, + eMinecraftColour_Material_Stone, + eMinecraftColour_Material_Water, + eMinecraftColour_Material_Wood, + eMinecraftColour_Material_Emerald, + + eMinecraftColour_Particle_Note_00, + eMinecraftColour_Particle_Note_01, + eMinecraftColour_Particle_Note_02, + eMinecraftColour_Particle_Note_03, + eMinecraftColour_Particle_Note_04, + eMinecraftColour_Particle_Note_05, + eMinecraftColour_Particle_Note_06, + eMinecraftColour_Particle_Note_07, + eMinecraftColour_Particle_Note_08, + eMinecraftColour_Particle_Note_09, + eMinecraftColour_Particle_Note_10, + eMinecraftColour_Particle_Note_11, + eMinecraftColour_Particle_Note_12, + eMinecraftColour_Particle_Note_13, + eMinecraftColour_Particle_Note_14, + eMinecraftColour_Particle_Note_15, + eMinecraftColour_Particle_Note_16, + eMinecraftColour_Particle_Note_17, + eMinecraftColour_Particle_Note_18, + eMinecraftColour_Particle_Note_19, + eMinecraftColour_Particle_Note_20, + eMinecraftColour_Particle_Note_21, + eMinecraftColour_Particle_Note_22, + eMinecraftColour_Particle_Note_23, + eMinecraftColour_Particle_Note_24, + + eMinecraftColour_Particle_NetherPortal, + eMinecraftColour_Particle_EnderPortal, + eMinecraftColour_Particle_Smoke, + eMinecraftColour_Particle_Ender, + eMinecraftColour_Particle_Explode, + eMinecraftColour_Particle_HugeExplosion, + eMinecraftColour_Particle_DripWater, + eMinecraftColour_Particle_DripLavaStart, + eMinecraftColour_Particle_DripLavaEnd, + eMinecraftColour_Particle_EnchantmentTable, + eMinecraftColour_Particle_DragonBreathMin, + eMinecraftColour_Particle_DragonBreathMax, + eMinecraftColour_Particle_Suspend, + eMinecraftColour_Particle_CritStart, + eMinecraftColour_Particle_CritEnd, + + eMinecraftColour_Effect_MovementSpeed, + eMinecraftColour_Effect_MovementSlowDown, + eMinecraftColour_Effect_DigSpeed, + eMinecraftColour_Effect_DigSlowdown, + eMinecraftColour_Effect_DamageBoost, + eMinecraftColour_Effect_Heal, + eMinecraftColour_Effect_Harm, + eMinecraftColour_Effect_Jump, + eMinecraftColour_Effect_Confusion, + eMinecraftColour_Effect_Regeneration, + eMinecraftColour_Effect_DamageResistance, + eMinecraftColour_Effect_FireResistance, + eMinecraftColour_Effect_WaterBreathing, + eMinecraftColour_Effect_Invisiblity, + eMinecraftColour_Effect_Blindness, + eMinecraftColour_Effect_NightVision, + eMinecraftColour_Effect_Hunger, + eMinecraftColour_Effect_Weakness, + eMinecraftColour_Effect_Poison, + + eMinecraftColour_Potion_BaseColour, + + eMinecraftColour_Mob_Creeper_Colour1, + eMinecraftColour_Mob_Creeper_Colour2, + eMinecraftColour_Mob_Skeleton_Colour1, + eMinecraftColour_Mob_Skeleton_Colour2, + eMinecraftColour_Mob_Spider_Colour1, + eMinecraftColour_Mob_Spider_Colour2, + eMinecraftColour_Mob_Zombie_Colour1, + eMinecraftColour_Mob_Zombie_Colour2, + eMinecraftColour_Mob_Slime_Colour1, + eMinecraftColour_Mob_Slime_Colour2, + eMinecraftColour_Mob_Ghast_Colour1, + eMinecraftColour_Mob_Ghast_Colour2, + eMinecraftColour_Mob_PigZombie_Colour1, + eMinecraftColour_Mob_PigZombie_Colour2, + eMinecraftColour_Mob_Enderman_Colour1, + eMinecraftColour_Mob_Enderman_Colour2, + eMinecraftColour_Mob_CaveSpider_Colour1, + eMinecraftColour_Mob_CaveSpider_Colour2, + eMinecraftColour_Mob_Silverfish_Colour1, + eMinecraftColour_Mob_Silverfish_Colour2, + eMinecraftColour_Mob_Blaze_Colour1, + eMinecraftColour_Mob_Blaze_Colour2, + eMinecraftColour_Mob_LavaSlime_Colour1, + eMinecraftColour_Mob_LavaSlime_Colour2, + eMinecraftColour_Mob_Pig_Colour1, + eMinecraftColour_Mob_Pig_Colour2, + eMinecraftColour_Mob_Sheep_Colour1, + eMinecraftColour_Mob_Sheep_Colour2, + eMinecraftColour_Mob_Cow_Colour1, + eMinecraftColour_Mob_Cow_Colour2, + eMinecraftColour_Mob_Chicken_Colour1, + eMinecraftColour_Mob_Chicken_Colour2, + eMinecraftColour_Mob_Squid_Colour1, + eMinecraftColour_Mob_Squid_Colour2, + eMinecraftColour_Mob_Wolf_Colour1, + eMinecraftColour_Mob_Wolf_Colour2, + eMinecraftColour_Mob_MushroomCow_Colour1, + eMinecraftColour_Mob_MushroomCow_Colour2, + eMinecraftColour_Mob_Ocelot_Colour1, + eMinecraftColour_Mob_Ocelot_Colour2, + eMinecraftColour_Mob_Villager_Colour1, + eMinecraftColour_Mob_Villager_Colour2, + + eMinecraftColour_Armour_Default_Leather_Colour, + + eMinecraftColour_Under_Water_Clear_Colour, + eMinecraftColour_Under_Lava_Clear_Colour, + eMinecraftColour_In_Cloud_Base_Colour, + + eMinecraftColour_Under_Water_Fog_Colour, + eMinecraftColour_Under_Lava_Fog_Colour, + eMinecraftColour_In_Cloud_Fog_Colour, + + eMinecraftColour_Default_Fog_Colour, + eMinecraftColour_Nether_Fog_Colour, + eMinecraftColour_End_Fog_Colour, + + eMinecraftColour_Sign_Text, + eMinecraftColour_Map_Text, + + eHTMLColor_0, + eHTMLColor_1, + eHTMLColor_2, + eHTMLColor_3, + eHTMLColor_4, + eHTMLColor_5, + eHTMLColor_6, + eHTMLColor_7, + eHTMLColor_8, + eHTMLColor_9, + eHTMLColor_a, + eHTMLColor_b, + eHTMLColor_c, + eHTMLColor_d, + eHTMLColor_e, + eHTMLColor_f, + eHTMLColor_0_dark, + eHTMLColor_1_dark, + eHTMLColor_2_dark, + eHTMLColor_3_dark, + eHTMLColor_4_dark, + eHTMLColor_5_dark, + eHTMLColor_6_dark, + eHTMLColor_7_dark, + eHTMLColor_8_dark, + eHTMLColor_9_dark, + eHTMLColor_a_dark, + eHTMLColor_b_dark, + eHTMLColor_c_dark, + eHTMLColor_d_dark, + eHTMLColor_e_dark, + eHTMLColor_f_dark, + eHTMLColor_T1, + eHTMLColor_T2, + eHTMLColor_T3, + eHTMLColor_Black, + eHTMLColor_White, + + eTextColor_Enchant, + eTextColor_EnchantFocus, + eTextColor_EnchantDisabled, + eTextColor_RenamedItemTitle, + + //eHTMLColor_0 = 0x000000, //r:0 , g: 0, b: 0, i: 0 + //eHTMLColor_1 = 0x0000aa, //r:0 , g: 0, b: aa, i: 1 + //eHTMLColor_2 = 0x109e10, // Changed by request of Dave //0x00aa00, //r:0 , g: aa, b: 0, i: 2 + //eHTMLColor_3 = 0x109e9e, // Changed by request of Dave //0x00aaaa, //r:0 , g: aa, b: aa, i: 3 + //eHTMLColor_4 = 0xaa0000, //r:aa , g: 0, b: 0, i: 4 + //eHTMLColor_5 = 0xaa00aa, //r:aa , g: 0, b: aa, i: 5 + //eHTMLColor_6 = 0xffaa00, //r:ff , g: aa, b: 0, i: 6 + //eHTMLColor_7 = 0xaaaaaa, //r:aa , g: aa, b: aa, i: 7 + //eHTMLColor_8 = 0x555555, //r:55 , g: 55, b: 55, i: 8 + //eHTMLColor_9 = 0x5555ff, //r:55 , g: 55, b: ff, i: 9 + //eHTMLColor_a = 0x55ff55, //r:55 , g: ff, b: 55, i: a + //eHTMLColor_b = 0x55ffff, //r:55 , g: ff, b: ff, i: b + //eHTMLColor_c = 0xff5555, //r:ff , g: 55, b: 55, i: c + //eHTMLColor_d = 0xff55ff, //r:ff , g: 55, b: ff, i: d + //eHTMLColor_e = 0xffff55, //r:ff , g: ff, b: 55, i: e + //eHTMLColor_f = 0xffffff, //r:ff , g: ff, b: ff, i: f + //eHTMLColor_0_dark = 0x000000, //r:0 , g: 0, b: 0, i: 10 + //eHTMLColor_1_dark = 0x00002a, //r:0 , g: 0, b: 2a, i: 11 + //eHTMLColor_2_dark = 0x002a00, //r:0 , g: 2a, b: 0, i: 12 + //eHTMLColor_3_dark = 0x002a2a, //r:0 , g: 2a, b: 2a, i: 13 + //eHTMLColor_4_dark = 0x2a0000, //r:2a , g: 0, b: 0, i: 14 + //eHTMLColor_5_dark = 0x2a002a, //r:2a , g: 0, b: 2a, i: 15 + //eHTMLColor_6_dark = 0x2a2a00, //r:2a , g: 2a, b: 0, i: 16 + //eHTMLColor_7_dark = 0x2a2a2a, //r:2a , g: 2a, b: 2a, i: 17 + //eHTMLColor_8_dark = 0x151515, //r:15 , g: 15, b: 15, i: 18 + //eHTMLColor_9_dark = 0x15153f, //r:15 , g: 15, b: 3f, i: 19 + //eHTMLColor_a_dark = 0x153f15, //r:15 , g: 3f, b: 15, i: 1a + //eHTMLColor_b_dark = 0x153f3f, //r:15 , g: 3f, b: 3f, i: 1b + //eHTMLColor_c_dark = 0x3f1515, //r:3f , g: 15, b: 15, i: 1c + //eHTMLColor_d_dark = 0x3f153f, //r:3f , g: 15, b: 3f, i: 1d + //eHTMLColor_e_dark = 0x3f3f15, //r:3f , g: 3f, b: 15, i: 1e + //eHTMLColor_f_dark = 0x3f3f3f, //r:3f , g: 3f, b: 3f, i: 1f + + eMinecraftColour_COUNT, +}; + +enum eDLCContentType +{ + e_DLC_SkinPack=0, + e_DLC_TexturePacks, + e_DLC_MashupPacks, + e_DLC_Themes, + e_DLC_AvatarItems, + e_DLC_Gamerpics, + e_DLC_MAX_MinecraftStore, + e_DLC_TexturePackData, // for the icon, banner and text + e_DLC_MAX, + e_DLC_NotDefined, +}; + +enum eDLCMarketplaceType +{ + e_Marketplace_Content=0, // skins, texture packs and mashup packs + e_Marketplace_Themes, + e_Marketplace_AvatarItems, + e_Marketplace_Gamerpics, + e_Marketplace_MAX, + e_Marketplace_NotDefined, +}; + +enum eDLCContentState +{ + e_DLC_ContentState_Idle = 0, + e_DLC_ContentState_Retrieving, + e_DLC_ContentState_Retrieved +}; + +enum eTMSContentState +{ + e_TMS_ContentState_Idle = 0, + e_TMS_ContentState_Queued, + e_TMS_ContentState_Retrieving, + e_TMS_ContentState_Retrieved +}; + +enum eXUID +{ + eXUID_Undefined=0, + eXUID_NoName, // name not needed + eXUID_Notch, + eXUID_Carl, + eXUID_Daniel, + eXUID_Deadmau5, + eXUID_DannyBStyle, + eXUID_JulianClark, + eXUID_Millionth, + eXUID_4JPaddy, + eXUID_4JStuart, + eXUID_4JDavid, + eXUID_4JRichard, + eXUID_4JSteven, +}; + + +enum _eTerrainFeatureType +{ + eTerrainFeature_None=0, + eTerrainFeature_Stronghold, + eTerrainFeature_Mineshaft, + eTerrainFeature_Village, + eTerrainFeature_Ravine, + eTerrainFeature_NetherFortress, + eTerrainFeature_StrongholdEndPortal, + eTerrainFeature_Count +}; + +// 4J Stu - Whend adding new options you should consider whether having them on should disable achievements, and if so add them to the CanRecordStatsAndAchievements function +// 4J Stu - These options are now saved in save data, so new options can ONLY be added to the end +enum eGameHostOption +{ + eGameHostOption_Difficulty=0, + eGameHostOption_OnlineGame, // Unused + eGameHostOption_InviteOnly, // Unused + eGameHostOption_FriendsOfFriends, + eGameHostOption_Gamertags, + eGameHostOption_Tutorial, // special case + eGameHostOption_GameType, + eGameHostOption_LevelType, // flat or default + eGameHostOption_Structures, + eGameHostOption_BonusChest, + eGameHostOption_HasBeenInCreative, + eGameHostOption_PvP, + eGameHostOption_TrustPlayers, + eGameHostOption_TNT, + eGameHostOption_FireSpreads, + eGameHostOption_CheatsEnabled, // special case + eGameHostOption_HostCanFly, + eGameHostOption_HostCanChangeHunger, + eGameHostOption_HostCanBeInvisible, + eGameHostOption_BedrockFog, + eGameHostOption_NoHUD, + eGameHostOption_All, + + eGameHostOption_DisableSaving, +}; + +// 4J-PB - If any new DLC items are added to the TMSFiles, this array needs updated +#ifdef _XBOX +enum _TMSFILES +{ + TMS_SP1=0, + TMS_SP2, + TMS_SP3, + TMS_SP4, + TMS_SP5, + TMS_SP6, + TMS_SPF, + TMS_SPB, + TMS_SPC, + TMS_SPZ, + TMS_SPM, + TMS_SPI, + TMS_SPG, + + TMS_THST, + TMS_THIR, + TMS_THGO, + TMS_THDI, + TMS_THAW, + + TMS_GPAN, + TMS_GPCO, + TMS_GPEN, + TMS_GPFO, + TMS_GPTO, + TMS_GPBA, + TMS_GPFA, + TMS_GPME, + TMS_GPMF, + TMS_GPMM, + TMS_GPSE, + TMS_GPOr, + TMS_GPMi, + TMS_GPMB, + TMS_GPBr, + TMS_GPM1, + TMS_GPM2, + TMS_GPM3, + + TMS_AH_0001, + TMS_AH_0002, + TMS_AH_0003, + TMS_AH_0004, + TMS_AH_0005, + TMS_AH_0006, + TMS_AH_0007, + TMS_AH_0008, + TMS_AH_0009, + TMS_AH_0010, + TMS_AH_0011, + TMS_AH_0012, + TMS_AH_0013, + + TMS_AT_0001, + TMS_AT_0002, + TMS_AT_0003, + TMS_AT_0004, + TMS_AT_0005, + TMS_AT_0006, + TMS_AT_0007, + TMS_AT_0008, + TMS_AT_0009, + TMS_AT_0010, + TMS_AT_0011, + TMS_AT_0012, + TMS_AT_0013, + TMS_AT_0014, + TMS_AT_0015, + TMS_AT_0016, + TMS_AT_0017, + TMS_AT_0018, + TMS_AT_0019, + TMS_AT_0020, + TMS_AT_0021, + TMS_AT_0022, + TMS_AT_0023, + TMS_AT_0024, + TMS_AT_0025, + TMS_AT_0026, + + TMS_AP_0001, + TMS_AP_0002, + TMS_AP_0003, + TMS_AP_0004, + TMS_AP_0005, + TMS_AP_0006, + TMS_AP_0007, + TMS_AP_0009, + TMS_AP_0010, + TMS_AP_0011, + TMS_AP_0012, + TMS_AP_0013, + TMS_AP_0014, + TMS_AP_0015, + TMS_AP_0016, + TMS_AP_0017, + TMS_AP_0018, + + TMS_AP_0019, + TMS_AP_0020, + TMS_AP_0021, + TMS_AP_0022, + TMS_AP_0023, + TMS_AP_0024, + TMS_AP_0025, + TMS_AP_0026, + TMS_AP_0027, + TMS_AP_0028, + TMS_AP_0029, + TMS_AP_0030, + TMS_AP_0031, + TMS_AP_0032, + TMS_AP_0033, + + TMS_AA_0001, + + TMS_MPMA, + TMS_MPMA_DAT, + TMS_MPSR, + TMS_MPSR_DAT, + TMS_MPHA, + TMS_MPHA_DAT, + + TMS_TP01, + TMS_TP01_DAT, + TMS_TP02, + TMS_TP02_DAT, + TMS_TP04, + TMS_TP04_DAT, + TMS_TP05, + TMS_TP05_DAT, + TMS_TP06, + TMS_TP06_DAT, + TMS_TP07, + TMS_TP07_DAT, + + TMS_COUNT +}; +#endif + +enum EHTMLFontSize +{ + eHTMLSize_Normal, + eHTMLSize_Splitscreen, + eHTMLSize_Tutorial, + eHTMLSize_EndPoem, + + eHTMLSize_COUNT, +}; + +enum EControllerActions +{ + ACTION_MENU_A, + ACTION_MENU_B, + ACTION_MENU_X, + ACTION_MENU_Y, + ACTION_MENU_UP, + ACTION_MENU_DOWN, + ACTION_MENU_RIGHT, + ACTION_MENU_LEFT, + ACTION_MENU_PAGEUP, + ACTION_MENU_PAGEDOWN, + ACTION_MENU_RIGHT_SCROLL, + ACTION_MENU_LEFT_SCROLL, + ACTION_MENU_STICK_PRESS, + ACTION_MENU_OTHER_STICK_PRESS, + ACTION_MENU_OTHER_STICK_UP, + ACTION_MENU_OTHER_STICK_DOWN, + ACTION_MENU_OTHER_STICK_LEFT, + ACTION_MENU_OTHER_STICK_RIGHT, + ACTION_MENU_PAUSEMENU, + +#ifdef _DURANGO + ACTION_MENU_GTC_PAUSE, + ACTION_MENU_GTC_RESUME, +#endif + +#ifdef __ORBIS__ + ACTION_MENU_TOUCHPAD_PRESS, +#endif + + ACTION_MENU_OK, + ACTION_MENU_CANCEL, + ACTION_MAX_MENU = ACTION_MENU_CANCEL, + + MINECRAFT_ACTION_JUMP, + MINECRAFT_ACTION_FORWARD, + MINECRAFT_ACTION_BACKWARD, + MINECRAFT_ACTION_LEFT, + MINECRAFT_ACTION_RIGHT, + MINECRAFT_ACTION_LOOK_LEFT, + MINECRAFT_ACTION_LOOK_RIGHT, + MINECRAFT_ACTION_LOOK_UP, + MINECRAFT_ACTION_LOOK_DOWN, + MINECRAFT_ACTION_USE, + MINECRAFT_ACTION_ACTION, + MINECRAFT_ACTION_LEFT_SCROLL, + MINECRAFT_ACTION_RIGHT_SCROLL, + MINECRAFT_ACTION_INVENTORY, + MINECRAFT_ACTION_PAUSEMENU, + MINECRAFT_ACTION_DROP, + MINECRAFT_ACTION_SNEAK_TOGGLE, + MINECRAFT_ACTION_CRAFTING, + MINECRAFT_ACTION_RENDER_THIRD_PERSON, + MINECRAFT_ACTION_GAME_INFO, + MINECRAFT_ACTION_DPAD_LEFT, + MINECRAFT_ACTION_DPAD_RIGHT, + MINECRAFT_ACTION_DPAD_UP, + MINECRAFT_ACTION_DPAD_DOWN, + + MINECRAFT_ACTION_MAX, + + // These 4 aren't mapped to the input manager directly but are created from the dpad controls if required in Minecraft::run_middle + // Don't use them with the input manager directly, just through LocalPlayer::ullButtonsPressed + MINECRAFT_ACTION_SPAWN_CREEPER, + MINECRAFT_ACTION_CHANGE_SKIN, + MINECRAFT_ACTION_FLY_TOGGLE, + MINECRAFT_ACTION_RENDER_DEBUG +}; + +enum eMCLang +{ + eMCLang_null=0, + eMCLang_enUS, + eMCLang_enGB, + eMCLang_enIE, + eMCLang_enAU, + eMCLang_enNZ, + eMCLang_enCA, + eMCLang_jaJP, + eMCLang_deDE, + eMCLang_deAT, + eMCLang_frFR, + eMCLang_frCA, + eMCLang_esES, + eMCLang_esMX, + eMCLang_itIT, + eMCLang_koKR, + eMCLang_ptPT, + eMCLang_ptBR, + eMCLang_ruRU, + eMCLang_nlNL, + eMCLang_fiFI, + eMCLang_svSV, + eMCLang_daDA, + eMCLang_noNO, + eMCLang_plPL, + eMCLang_trTR, + eMCLang_elEL, + eMCLang_zhCHS, + eMCLang_zhCHT, + eMCLang_laLAS, + + eMCLang_zhSG, + eMCLang_zhCN, + eMCLang_zhHK, + eMCLang_zhTW, + eMCLang_nlBE, + eMCLang_daDK, + eMCLang_frBE, + eMCLang_frCH, + eMCLang_deCH, + eMCLang_nbNO, + eMCLang_enGR, + eMCLang_enHK, + eMCLang_enSA, + eMCLang_enHU, + eMCLang_enIN, + eMCLang_enIL, + eMCLang_enSG, + eMCLang_enSK, + eMCLang_enZA, + eMCLang_enCZ, + eMCLang_enAE, + eMCLang_esAR, + eMCLang_esCL, + eMCLang_esCO, + eMCLang_esUS, + eMCLang_svSE, + + eMCLang_csCZ, + eMCLang_elGR, + eMCLang_nnNO, + eMCLang_skSK, +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/App_structs.h b/Minecraft.Client/Common/App_structs.h new file mode 100644 index 0000000..ed321b5 --- /dev/null +++ b/Minecraft.Client/Common/App_structs.h @@ -0,0 +1,227 @@ +#pragma once + +typedef struct +{ + wchar_t *wchFilename; + eFileExtensionType eEXT; + eTMSFileType eTMSType; + PBYTE pbData; + UINT uiSize; + int iConfig; // used for texture pack data files +} +TMS_FILE; + +typedef struct +{ + PBYTE pbData; + DWORD dwBytes; + BYTE ucRefCount; +} +MEMDATA,*PMEMDATA; + +typedef struct +{ + DWORD dwNotification; + UINT uiParam; +} +NOTIFICATION,*PNOTIFICATION; + +typedef struct +{ + bool bSettingsChanged; + unsigned char ucMusicVolume; + unsigned char ucSoundFXVolume; + unsigned char ucSensitivity; + unsigned char ucGamma; + unsigned char ucPad01; // 1 byte of padding inserted here + unsigned short usBitmaskValues; // bit 0,1 - difficulty + // bit 2 - view bob + // bit 3 - player visible in a map + // bit 4,5 - control scheme + // bit 6 - invert look + // bit 7 - southpaw + // bit 8 - splitscreen vertical + + // 4J-PB - Adding new values for interim TU for 1.6.6 + // bit 9 - Display gamertags in splitscreen + // bit 10 - Disable/Enable hints + // bit 11,12,13,14 - Autosave frequency - 0 = Off, 8 = (8*15 minutes) = 2 hours + // bit 15 Tooltips + + // debug values + unsigned int uiDebugBitmask; + + // block off space to use for whatever we want (e.g bitflags for storing things the player has done in the game, so we can flag the first time they do things, such as sleep) + union + { + struct + { + unsigned char ucTutorialCompletion[TUTORIAL_PROFILE_STORAGE_BYTES]; + // adding new flags for interim TU to 1.6.6 + + // A value that encodes the skin that the player has set as their default + DWORD dwSelectedSkin; + + // In-Menu sensitivity + unsigned char ucMenuSensitivity; + unsigned char ucInterfaceOpacity; + unsigned char ucPad02;//2 bytes of padding added here + unsigned char usPad03; + + // Adding another bitmask flag for more settings for 1.8.2 + unsigned int uiBitmaskValues; // 0x00000001 - eGameSetting_Clouds - on + // 0x00000002 - eGameSetting_GameSetting_Online - on + // 0x00000004 - eGameSetting_GameSetting_Invite - off + // 0x00000008 - eGameSetting_GameSetting_FriendsOfFriends - on + // 0x00000010 - eGameSetting_PSVita_NetworkModeAdhoc - on + + // TU 5 + // 0x00000030 - eGameSetting_DisplayUpdateMessage - 3 - counts down to zero + // TU 6 + // 0x00000040 - eGameSetting_BedrockFog - off + // 0x00000080 - eGameSetting_DisplayHUD - on + // 0x00000100 - eGameSetting_DisplayHand - on + // TU 7 + // 0x00000200 - eGameSetting_CustomSkinAnim - on + + // TU9 // 0x00000400 - eGameSetting_DeathMessages - on + + // Adding another bitmask to store "special" completion tasks for the tutorial + unsigned int uiSpecialTutorialBitmask; + + // A value that encodes the cape that the player has set + DWORD dwSelectedCape; + + unsigned int uiFavoriteSkinA[MAX_FAVORITE_SKINS]; + unsigned char ucCurrentFavoriteSkinPos; + + // TU13 + unsigned int uiMashUpPackWorldsDisplay; // bitmask to enable/disable the display of the individual mash-up pack worlds + + // PS3 1.05 - Adding Greek, so need a language + unsigned char ucLanguage; + // 4J Stu - See comment for GAME_SETTINGS_PROFILE_DATA_BYTES below + // was 192 + //unsigned char ucUnused[192-TUTORIAL_PROFILE_STORAGE_BYTES-sizeof(DWORD)-sizeof(char)-sizeof(char)-sizeof(char)-sizeof(char)-sizeof(LONG)-sizeof(LONG)-sizeof(DWORD)]; + // 4J-PB - don't need to define the padded space, the union with ucReservedSpace will make the sizeof GAME_SETTINGS correct + }; + + unsigned char ucReservedSpace[192]; + + + }; +} +GAME_SETTINGS; + +#ifdef _XBOX_ONE +typedef struct +{ + WCHAR wchPlayerUID[64]; + char pszLevelName[14]; +} +BANNEDLISTDATA,*PBANNEDLISTDATA; +#else +typedef struct +{ + PlayerUID xuid; + char pszLevelName[14]; +} +BANNEDLISTDATA,*PBANNEDLISTDATA; +#endif + +typedef std::vector VBANNEDLIST; + +typedef struct +{ + int iPad; + eXuiAction action; +} +XuiActionParam; + +// tips +typedef struct +{ + int iSortValue; + UINT uiStringID; +} +TIPSTRUCT; + + +typedef struct +{ + eXUID eXuid; + WCHAR wchCape[MAX_CAPENAME_SIZE]; + WCHAR wchSkin[MAX_CAPENAME_SIZE]; +} +MOJANG_DATA; + +typedef struct +{ + eDLCContentType eDLCType; +#if defined( __PS3__) || defined(__ORBIS__) || defined (__PSVITA__) + char chImageURL[256];//SCE_NP_COMMERCE2_URL_LEN +#else + +#ifdef _XBOX_ONE + + wstring wsProductId; + wstring wsDisplayName; + + // add a store for the local DLC image + PBYTE pbImageData; + DWORD dwImageBytes; +#else + ULONGLONG ullOfferID_Full; + ULONGLONG ullOfferID_Trial; +#endif + WCHAR wchBanner[MAX_BANNERNAME_SIZE]; + WCHAR wchDataFile[MAX_BANNERNAME_SIZE]; + int iGender; +#endif + int iConfig; + unsigned int uiSortIndex; +} +DLC_INFO; + + +typedef struct +{ + int x,z; + _eTerrainFeatureType eTerrainFeature; +} +FEATURE_DATA; + +// banned list +typedef struct +{ + BYTE *pBannedList; + DWORD dwBytes; +} +BANNEDLIST; + +typedef struct _DLCRequest +{ + DWORD dwType; + eDLCContentState eState; +} +DLCRequest; + +typedef struct _TMSPPRequest +{ + eTMSContentState eState; + eDLCContentType eType; + C4JStorage::eGlobalStorage eStorageFacility; + C4JStorage::eTMS_FILETYPEVAL eFileTypeVal; + //char szFilename[MAX_TMSFILENAME_SIZE]; +#ifdef _XBOX_ONE + int( *CallbackFunc)(LPVOID,int,int,LPVOID, WCHAR *); +#else + int( *CallbackFunc)(LPVOID,int,int,C4JStorage::PTMSPP_FILEDATA, LPCSTR szFilename); +#endif + WCHAR wchFilename[MAX_TMSFILENAME_SIZE]; + + LPVOID lpCallbackParam; +} +TMSPPRequest; + +typedef pair SceneStackPair; diff --git a/Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp new file mode 100644 index 0000000..269b605 --- /dev/null +++ b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.cpp @@ -0,0 +1,38 @@ +#include "stdafx.h" +#include "Consoles_SoundEngine.h" + + +bool ConsoleSoundEngine::GetIsPlayingStreamingCDMusic() +{ + return m_bIsPlayingStreamingCDMusic; +} +bool ConsoleSoundEngine::GetIsPlayingStreamingGameMusic() +{ + return m_bIsPlayingStreamingGameMusic; +} +void ConsoleSoundEngine::SetIsPlayingStreamingCDMusic(bool bVal) +{ + m_bIsPlayingStreamingCDMusic=bVal; +} +void ConsoleSoundEngine::SetIsPlayingStreamingGameMusic(bool bVal) +{ + m_bIsPlayingStreamingGameMusic=bVal; +} +bool ConsoleSoundEngine::GetIsPlayingEndMusic() +{ + return m_bIsPlayingEndMusic; +} +bool ConsoleSoundEngine::GetIsPlayingNetherMusic() +{ + return m_bIsPlayingNetherMusic; +} +void ConsoleSoundEngine::SetIsPlayingEndMusic(bool bVal) +{ + m_bIsPlayingEndMusic=bVal; +} +void ConsoleSoundEngine::SetIsPlayingNetherMusic(bool bVal) +{ + m_bIsPlayingNetherMusic=bVal; +} + + diff --git a/Minecraft.Client/Common/Audio/Consoles_SoundEngine.h b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.h new file mode 100644 index 0000000..4ec7603 --- /dev/null +++ b/Minecraft.Client/Common/Audio/Consoles_SoundEngine.h @@ -0,0 +1,81 @@ +#pragma once + +#include "..\..\..\Minecraft.World\SoundTypes.h" + +#ifdef _XBOX + +#elif defined (__PS3__) +#undef __in +#undef __out +#include "..\..\PS3\Miles\include\mss.h" +#elif defined (__PSVITA__) +#include "..\..\PSVITA\Miles\include\mss.h" +#elif defined _DURANGO +// 4J Stu - Temp define to get Miles to link, can likely be removed when we get a new version of Miles +#define _SEKRIT +#include "..\..\Durango\Miles\include\mss.h" +#elif defined _WINDOWS64 +#include "..\..\windows64\Miles\include\mss.h" +#else // PS4 +// 4J Stu - Temp define to get Miles to link, can likely be removed when we get a new version of Miles +#define _SEKRIT2 +#include "..\..\Orbis\Miles\include\mss.h" +#endif + +typedef struct +{ + float x,y,z; +} +AUDIO_VECTOR; + +typedef struct +{ + bool bValid; + AUDIO_VECTOR vPosition; + AUDIO_VECTOR vOrientFront; +} +AUDIO_LISTENER; + +class Options; + +class ConsoleSoundEngine +{ +public: + + ConsoleSoundEngine() : m_bIsPlayingStreamingCDMusic(false),m_bIsPlayingStreamingGameMusic(false), m_bIsPlayingEndMusic(false),m_bIsPlayingNetherMusic(false){}; + virtual void tick(shared_ptr *players, float a) =0; + virtual void destroy()=0; + virtual void play(int iSound, float x, float y, float z, float volume, float pitch) =0; + virtual void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true) =0; + virtual void playUI(int iSound, float volume, float pitch) =0; + virtual void updateMusicVolume(float fVal) =0; + virtual void updateSystemMusicPlaying(bool isPlaying) = 0; + virtual void updateSoundEffectVolume(float fVal) =0; + virtual void init(Options *) =0 ; + virtual void add(const wstring& name, File *file) =0; + virtual void addMusic(const wstring& name, File *file) =0; + virtual void addStreaming(const wstring& name, File *file) =0; + virtual char *ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) =0; + virtual void playMusicTick() =0; + + virtual bool GetIsPlayingStreamingCDMusic() ; + virtual bool GetIsPlayingStreamingGameMusic() ; + virtual void SetIsPlayingStreamingCDMusic(bool bVal) ; + virtual void SetIsPlayingStreamingGameMusic(bool bVal) ; + virtual bool GetIsPlayingEndMusic() ; + virtual bool GetIsPlayingNetherMusic() ; + virtual void SetIsPlayingEndMusic(bool bVal) ; + virtual void SetIsPlayingNetherMusic(bool bVal) ; + static const WCHAR *wchSoundNames[eSoundType_MAX]; + static const WCHAR *wchUISoundNames[eSFX_MAX]; + +private: + // platform specific functions + + virtual int initAudioHardware(int iMinSpeakers)=0; + + bool m_bIsPlayingStreamingCDMusic; + bool m_bIsPlayingStreamingGameMusic; + bool m_bIsPlayingEndMusic; + bool m_bIsPlayingNetherMusic; +}; diff --git a/Minecraft.Client/Common/Audio/SoundEngine.cpp b/Minecraft.Client/Common/Audio/SoundEngine.cpp new file mode 100644 index 0000000..4eaf7df --- /dev/null +++ b/Minecraft.Client/Common/Audio/SoundEngine.cpp @@ -0,0 +1,1668 @@ +#include "stdafx.h" + +#include "SoundEngine.h" +#include "..\Consoles_App.h" +#include "..\..\MultiplayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\Minecraft.World\leveldata.h" +#include "..\..\Minecraft.World\mth.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\DLCTexturePack.h" +#include "Common\DLC\DLCAudioFile.h" + +#ifdef __PSVITA__ +#include +#endif + +#ifdef _WINDOWS64 +#include "..\..\Minecraft.Client\Windows64\Windows64_App.h" +#include "..\..\Minecraft.Client\Windows64\Miles\include\imssapi.h" +#endif + +#ifdef __ORBIS__ +#include +//#define __DISABLE_MILES__ // MGH disabled for now as it crashes if we call sceNpMatching2Initialize +#endif + +// take out Orbis until they are done +#if defined _XBOX + +SoundEngine::SoundEngine() {} +void SoundEngine::init(Options *pOptions) +{ +} + +void SoundEngine::tick(shared_ptr *players, float a) +{ +} +void SoundEngine::destroy() {} +void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) +{ + app.DebugPrintf("PlaySound - %d\n",iSound); +} +void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay) {} +void SoundEngine::playUI(int iSound, float volume, float pitch) {} + +void SoundEngine::updateMusicVolume(float fVal) {} +void SoundEngine::updateSoundEffectVolume(float fVal) {} + +void SoundEngine::add(const wstring& name, File *file) {} +void SoundEngine::addMusic(const wstring& name, File *file) {} +void SoundEngine::addStreaming(const wstring& name, File *file) {} +char *SoundEngine::ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) { return NULL; } +bool SoundEngine::isStreamingWavebankReady() { return true; } +void SoundEngine::playMusicTick() {}; + +#else + +#ifdef _WINDOWS64 +char SoundEngine::m_szSoundPath[]={"Durango\\Sound\\"}; +char SoundEngine::m_szMusicPath[]={"music\\"}; +char SoundEngine::m_szRedistName[]={"redist64"}; +#elif defined _DURANGO +char SoundEngine::m_szSoundPath[]={"Sound\\"}; +char SoundEngine::m_szMusicPath[]={"music\\"}; +char SoundEngine::m_szRedistName[]={"redist64"}; +#elif defined __ORBIS__ + +#ifdef _CONTENT_PACKAGE +char SoundEngine::m_szSoundPath[]={"Sound/"}; +#elif defined _ART_BUILD +char SoundEngine::m_szSoundPath[]={"Sound/"}; +#else +// just use the host Durango folder for the sound. In the content package, we'll have moved this in the .gp4 file +char SoundEngine::m_szSoundPath[]={"Durango/Sound/"}; +#endif +char SoundEngine::m_szMusicPath[]={"music/"}; +char SoundEngine::m_szRedistName[]={"redist64"}; +#elif defined __PSVITA__ +char SoundEngine::m_szSoundPath[]={"PSVita/Sound/"}; +char SoundEngine::m_szMusicPath[]={"music/"}; +char SoundEngine::m_szRedistName[]={"redist"}; +#elif defined __PS3__ +//extern const char* getPS3HomePath(); +char SoundEngine::m_szSoundPath[]={"PS3/Sound/"}; +char SoundEngine::m_szMusicPath[]={"music/"}; +char SoundEngine::m_szRedistName[]={"redist"}; + +#define USE_SPURS + +#ifdef USE_SPURS +#include +#else +#include +#endif + +#endif + +F32 AILCALLBACK custom_falloff_function (HSAMPLE S, + F32 distance, + F32 rolloff_factor, + F32 min_dist, + F32 max_dist); + +char *SoundEngine::m_szStreamFileA[eStream_Max]= +{ + "calm1", + "calm2", + "calm3", + "hal1", + "hal2", + "hal3", + "hal4", + "nuance1", + "nuance2", +#ifndef _XBOX + // add the new music tracks + "creative1", + "creative2", + "creative3", + "creative4", + "creative5", + "creative6", + "menu1", + "menu2", + "menu3", + "menu4", +#endif + "piano1", + "piano2", + "piano3", + + // Nether + "nether1", + "nether2", + "nether3", + "nether4", + // The End + "the_end_dragon_alive", + "the_end_end", + // CDs + "11", + "13", + "blocks", + "cat", + "chirp", + "far", + "mall", + "mellohi", + "stal", + "strad", + "ward", + "where_are_we_now" +}; + +///////////////////////////////////////////// +// +// ErrorCallback +// +///////////////////////////////////////////// +void AILCALL ErrorCallback(S64 i_Id, char const* i_Details) +{ + char *pchLastError=AIL_last_error(); + + if(pchLastError[0]!=0) + { + app.DebugPrintf("\rErrorCallback Error Category: %s\n", pchLastError); + } + + if (i_Details) + { + app.DebugPrintf("ErrorCallback - Details: %s\n", i_Details); + } +} + +#ifdef __PSVITA__ +// AP - this is the callback when the driver is about to mix. At this point the mutex is locked by Miles so we can now call all Miles functions without +// the possibility of incurring a stall. +static bool SoundEngine_Change = false; // has tick been called? +static CRITICAL_SECTION SoundEngine_MixerMutex; + +void AILCALL MilesMixerCB(HDIGDRIVER dig) +{ + // has the tick function been called since the last callback + if( SoundEngine_Change ) + { + SoundEngine_Change = false; + + EnterCriticalSection(&SoundEngine_MixerMutex); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->soundEngine->updateMiles(); + pMinecraft->soundEngine->playMusicUpdate(); + + LeaveCriticalSection(&SoundEngine_MixerMutex); + } +} +#endif + +///////////////////////////////////////////// +// +// init +// +///////////////////////////////////////////// +void SoundEngine::init(Options *pOptions) +{ + app.DebugPrintf("---SoundEngine::init\n"); +#ifdef __DISABLE_MILES__ + return; +#endif +#ifdef __ORBIS__ + C4JThread::PushAffinityAllCores(); +#endif +#if defined _DURANGO || defined __ORBIS__ || defined __PS3__ || defined __PSVITA__ + Register_RIB(BinkADec); +#endif + + char *redistpath; + +#if (defined _WINDOWS64 || defined __PSVITA__)// || defined _DURANGO || defined __ORBIS__ ) + redistpath=AIL_set_redist_directory(m_szRedistName); +#endif + + app.DebugPrintf("---SoundEngine::init - AIL_startup\n"); + S32 ret = AIL_startup(); + + int iNumberOfChannels=initAudioHardware(8); + + // Create a driver to render our audio - 44khz, 16 bit, +#ifdef __PS3__ + // On the Sony PS3, the driver is always opened in 48 kHz, 32-bit floating point. The only meaningful configurations are MSS_MC_STEREO, MSS_MC_51_DISCRETE, and MSS_MC_71_DISCRETE. + m_hDriver = AIL_open_digital_driver( 48000, 16, iNumberOfChannels, AIL_OPEN_DIGITAL_USE_SPU0 ); +#elif defined __PSVITA__ + + // maximum of 16 samples + AIL_set_preference(DIG_MIXER_CHANNELS, 16); + + m_hDriver = AIL_open_digital_driver( 48000, 16, MSS_MC_STEREO, 0 ); + + // AP - For some reason the submit thread defaults to a priority of zero (invalid). Make sure it has the highest priority to avoid audio breakup. + SceUID threadID; + AIL_platform_property( m_hDriver, PSP2_SUBMIT_THREAD, &threadID, 0, 0); + S32 g_DefaultCPU = sceKernelGetThreadCpuAffinityMask(threadID); + S32 Old = sceKernelChangeThreadPriority(threadID, 64); + + // AP - register a callback when the mixer starts + AILMIXERCB temp = AIL_register_mix_callback(m_hDriver, MilesMixerCB); + + InitializeCriticalSection(&SoundEngine_MixerMutex); + +#elif defined(__ORBIS__) + m_hDriver = AIL_open_digital_driver( 48000, 16, 2, 0 ); + app.DebugPrintf("---SoundEngine::init - AIL_open_digital_driver\n"); + +#else + m_hDriver = AIL_open_digital_driver(44100, 16, MSS_MC_USE_SYSTEM_CONFIG, 0); +#endif + if (m_hDriver == 0) + { + app.DebugPrintf("Couldn't open digital sound driver. (%s)\n", AIL_last_error()); + AIL_shutdown(); +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + return; + } + app.DebugPrintf("---SoundEngine::init - driver opened\n"); + +#ifdef __PSVITA__ + + // set high falloff power for maximum spatial effect in software mode + AIL_set_speaker_configuration( m_hDriver, 0, 0, 4.0F ); + +#endif + + AIL_set_event_error_callback(ErrorCallback); + + AIL_set_3D_rolloff_factor(m_hDriver,1.0); + + // Create an event system tied to that driver - let Miles choose memory defaults. + //if (AIL_startup_event_system(m_hDriver, 0, 0, 0) == 0) + // 4J-PB - Durango complains that the default memory (64k)isn't enough + // Error: MilesEvent: Out of event system memory (pool passed to event system startup exhausted). + // AP - increased command buffer from the default 5K to 20K for Vita + + if (AIL_startup_event_system(m_hDriver, 1024*20, 0, 1024*128) == 0) + { + app.DebugPrintf("Couldn't init event system (%s).\n", AIL_last_error()); + AIL_close_digital_driver(m_hDriver); + AIL_shutdown(); +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + app.DebugPrintf("---SoundEngine::init - AIL_startup_event_system failed\n"); + return; + } + char szBankName[255]; +#if defined __PS3__ + if(app.GetBootedFromDiscPatch()) + { + char szTempSoundFilename[255]; + sprintf(szTempSoundFilename,"%s%s",m_szSoundPath, "Minecraft.msscmp" ); + + app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) looking for %s\n",szTempSoundFilename); + sprintf(szBankName,"%s/%s",app.GetBDUsrDirPath(szTempSoundFilename), m_szSoundPath ); + app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) music path - %s\n",szBankName); + } + else + { + sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); + } + +#elif defined __PSVITA__ + sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); +#elif defined __ORBIS__ + sprintf(szBankName,"%s/%s",getUsrDirPath(), m_szSoundPath ); +#else + strcpy((char *)szBankName,m_szSoundPath); +#endif + + strcat((char *)szBankName,"Minecraft.msscmp"); + + m_hBank=AIL_add_soundbank(szBankName, 0); + + if(m_hBank == NULL) + { + char *Error=AIL_last_error(); + app.DebugPrintf("Couldn't open soundbank: %s (%s)\n", szBankName, Error); + AIL_close_digital_driver(m_hDriver); + AIL_shutdown(); +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + return; + } + + //#ifdef _DEBUG + HMSSENUM token = MSS_FIRST; + char const* Events[1] = {0}; + S32 EventCount = 0; + while (AIL_enumerate_events(m_hBank, &token, 0, &Events[0])) + { + app.DebugPrintf(4,"%d - %s\n", EventCount, Events[0]); + + EventCount++; + } + //#endif + + U64 u64Result; + u64Result=AIL_enqueue_event_by_name("Minecraft/CacheSounds"); + + m_MasterMusicVolume=1.0f; + m_MasterEffectsVolume=1.0f; + + //AIL_set_variable_float(0,"UserEffectVol",1); + + m_bSystemMusicPlaying = false; + + m_openStreamThread = NULL; + +#ifdef __ORBIS__ + C4JThread::PopAffinity(); +#endif + +#ifdef __PSVITA__ + // AP - By default the mixer won't start up and nothing will process. Kick off a blank sample to force the mixer to start up. + HSAMPLE Sample = AIL_allocate_sample_handle(m_hDriver); + AIL_init_sample(Sample, DIG_F_STEREO_16); + static U64 silence = 0; + AIL_set_sample_address(Sample, &silence, sizeof(U64)); + AIL_start_sample(Sample); + + // wait for 1 mix... + AIL_release_sample_handle(Sample); +#endif +} + +#ifdef __ORBIS__ +// void SoundEngine::SetHandle(int32_t hAudio) +// { +// //m_hAudio=hAudio; +// } +#endif + +void SoundEngine::SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1) +{ + m_iStream_Overworld_Min=iOverworldMin; + m_iStream_Overworld_Max=iOverWorldMax; + m_iStream_Nether_Min=iNetherMin; + m_iStream_Nether_Max=iNetherMax; + m_iStream_End_Min=iEndMin; + m_iStream_End_Max=iEndMax; + m_iStream_CD_1=iCD1; + + // array to monitor recently played tracks + if(m_bHeardTrackA) + { + delete [] m_bHeardTrackA; + } + m_bHeardTrackA = new bool[iEndMax+1]; + memset(m_bHeardTrackA,0,sizeof(bool)*iEndMax+1); +} + +// AP - moved to a separate function so it can be called from the mixer callback on Vita +void SoundEngine::updateMiles() +{ +#ifdef __PSVITA__ + //CD - We must check for Background Music [BGM] at any point + //If it's playing disable our audio, otherwise enable + int NoBGMPlaying = sceAudioOutGetAdopt(SCE_AUDIO_OUT_PORT_TYPE_BGM); + updateSystemMusicPlaying( !NoBGMPlaying ); +#elif defined __ORBIS__ + // is the system playing background music? + SceAudioOutPortState outPortState; + sceAudioOutGetPortState(m_hBGMAudio,&outPortState); + updateSystemMusicPlaying( outPortState.output==SCE_AUDIO_OUT_STATE_OUTPUT_UNKNOWN ); +#endif + + if( m_validListenerCount == 1 ) + { + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + // set the listener as the first player we find + if( m_ListenerA[i].bValid ) + { + AIL_set_listener_3D_position(m_hDriver,m_ListenerA[i].vPosition.x,m_ListenerA[i].vPosition.y,-m_ListenerA[i].vPosition.z); // Flipped sign of z as Miles is expecting left handed coord system + AIL_set_listener_3D_orientation(m_hDriver,-m_ListenerA[i].vOrientFront.x,m_ListenerA[i].vOrientFront.y,m_ListenerA[i].vOrientFront.z,0,1,0); // Flipped sign of z as Miles is expecting left handed coord system + break; + } + } + } + else + { + // 4J-PB - special case for splitscreen + // the shortest distance between any listener and a sound will be used to play a sound a set distance away down the z axis. + // The listener position will be set to 0,0,0, and the orientation will be facing down the z axis + + AIL_set_listener_3D_position(m_hDriver,0,0,0); + AIL_set_listener_3D_orientation(m_hDriver,0,0,1,0,1,0); + } + + AIL_begin_event_queue_processing(); + + // Iterate over the sounds + S32 StartedCount = 0, CompletedCount = 0, TotalCount = 0; + HMSSENUM token = MSS_FIRST; + MILESEVENTSOUNDINFO SoundInfo; + int Playing = 0; + while (AIL_enumerate_sound_instances(0, &token, 0, 0, 0, &SoundInfo)) + { + AUDIO_INFO* game_data= (AUDIO_INFO*)( SoundInfo.UserBuffer ); + + if( SoundInfo.Status == MILESEVENT_SOUND_STATUS_PLAYING ) + { + Playing += 1; + } + + if ( SoundInfo.Status != MILESEVENT_SOUND_STATUS_COMPLETE ) + { + // apply the master volume + // watch for the 'special' volume levels + bool isThunder = false; + if( game_data->volume == 10000.0f ) + { + isThunder = true; + } + if(game_data->volume>1) + { + game_data->volume=1; + } + AIL_set_sample_volume_levels( SoundInfo.Sample, game_data->volume*m_MasterEffectsVolume, game_data->volume*m_MasterEffectsVolume); + + float distanceScaler = 16.0f; + switch(SoundInfo.Status) + { + case MILESEVENT_SOUND_STATUS_PENDING: + // 4J-PB - causes the falloff to be calculated on the PPU instead of the SPU, and seems to resolve our distorted sound issue + AIL_register_falloff_function_callback(SoundInfo.Sample,&custom_falloff_function); + + if(game_data->bIs3D) + { + AIL_set_sample_is_3D( SoundInfo.Sample, 1 ); + + int iSound = game_data->iSound - eSFX_MAX; + switch(iSound) + { + // Is this the Dragon? + case eSoundType_MOB_ENDERDRAGON_GROWL: + case eSoundType_MOB_ENDERDRAGON_MOVE: + case eSoundType_MOB_ENDERDRAGON_END: + case eSoundType_MOB_ENDERDRAGON_HIT: + distanceScaler=100.0f; + break; + case eSoundType_MOB_GHAST_MOAN: + case eSoundType_MOB_GHAST_SCREAM: + case eSoundType_MOB_GHAST_DEATH: + case eSoundType_MOB_GHAST_CHARGE: + case eSoundType_MOB_GHAST_FIREBALL: + distanceScaler=30.0f; + break; + } + + // Set a special distance scaler for thunder, which we respond to by having no attenutation + if( isThunder ) + { + distanceScaler = 10000.0f; + } + } + else + { + AIL_set_sample_is_3D( SoundInfo.Sample, 0 ); + } + + AIL_set_sample_3D_distances(SoundInfo.Sample,distanceScaler,1,0); + // set the pitch + if(!game_data->bUseSoundsPitchVal) + { + AIL_set_sample_playback_rate_factor(SoundInfo.Sample,game_data->pitch); + } + + if(game_data->bIs3D) + { + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-game_data->x); + y=fabs(m_ListenerA[i].vPosition.y-game_data->y); + z=fabs(m_ListenerA[i].vPosition.z-game_data->z); + fDist=x+y+z; + + if(fDistx, game_data->y, -game_data->z ); // Flipped sign of z as Miles is expecting left handed coord system + } + } + break; + + default: + if(game_data->bIs3D) + { + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-game_data->x); + y=fabs(m_ListenerA[i].vPosition.y-game_data->y); + z=fabs(m_ListenerA[i].vPosition.z-game_data->z); + fDist=x+y+z; + + if(fDistx, game_data->y, -game_data->z ); // Flipped sign of z as Miles is expecting left handed coord system + } + } + break; + } + } + } + AIL_complete_event_queue_processing(); +} + +//#define DISTORTION_TEST +#ifdef DISTORTION_TEST +static float fVal=0.0f; +#endif +///////////////////////////////////////////// +// +// tick +// +///////////////////////////////////////////// + +#ifdef __PSVITA__ +static S32 running = AIL_ms_count(); +#endif + +void SoundEngine::tick(shared_ptr *players, float a) +{ +#ifdef __DISABLE_MILES__ + return; +#endif + +#ifdef __PSVITA__ + EnterCriticalSection(&SoundEngine_MixerMutex); +#endif + + // update the listener positions + int listenerCount = 0; +#ifdef DISTORTION_TEST + float fX,fY,fZ; +#endif + if( players ) + { + bool bListenerPostionSet=false; + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( players[i] != NULL ) + { + m_ListenerA[i].bValid=true; + F32 x,y,z; + x=players[i]->xo + (players[i]->x - players[i]->xo) * a; + y=players[i]->yo + (players[i]->y - players[i]->yo) * a; + z=players[i]->zo + (players[i]->z - players[i]->zo) * a; + + float yRot = players[i]->yRotO + (players[i]->yRot - players[i]->yRotO) * a; + float yCos = (float)cos(-yRot * Mth::RAD_TO_GRAD - PI); + float ySin = (float)sin(-yRot * Mth::RAD_TO_GRAD - PI); + + // store the listener positions for splitscreen + m_ListenerA[i].vPosition.x = x; + m_ListenerA[i].vPosition.y = y; + m_ListenerA[i].vPosition.z = z; + + m_ListenerA[i].vOrientFront.x = ySin; + m_ListenerA[i].vOrientFront.y = 0; + m_ListenerA[i].vOrientFront.z = yCos; + + listenerCount++; + } + else + { + m_ListenerA[i].bValid=false; + } + } + } + + + // If there were no valid players set, make up a default listener + if( listenerCount == 0 ) + { + m_ListenerA[0].vPosition.x = 0; + m_ListenerA[0].vPosition.y = 0; + m_ListenerA[0].vPosition.z = 0; + m_ListenerA[0].vOrientFront.x = 0; + m_ListenerA[0].vOrientFront.y = 0; + m_ListenerA[0].vOrientFront.z = 1.0f; + listenerCount++; + } + m_validListenerCount = listenerCount; + +#ifdef __PSVITA__ + // AP - Show that a change has occurred so we know to update the values at the next Mixer callback + SoundEngine_Change = true; + + LeaveCriticalSection(&SoundEngine_MixerMutex); +#else + updateMiles(); +#endif +} + +///////////////////////////////////////////// +// +// SoundEngine +// +///////////////////////////////////////////// +SoundEngine::SoundEngine() +{ + random = new Random(); + m_hStream=0; + m_StreamState=eMusicStreamState_Idle; + m_iMusicDelay=0; + m_validListenerCount=0; + + m_bHeardTrackA=NULL; + + // Start the streaming music playing some music from the overworld + SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3, + eStream_Nether1,eStream_Nether4, + eStream_end_dragon,eStream_end_end, + eStream_CD_1); + + m_musicID=getMusicID(LevelData::DIMENSION_OVERWORLD); + + m_StreamingAudioInfo.bIs3D=false; + m_StreamingAudioInfo.x=0; + m_StreamingAudioInfo.y=0; + m_StreamingAudioInfo.z=0; + m_StreamingAudioInfo.volume=1; + m_StreamingAudioInfo.pitch=1; + + memset(CurrentSoundsPlaying,0,sizeof(int)*(eSoundType_MAX+eSFX_MAX)); + memset(m_ListenerA,0,sizeof(AUDIO_LISTENER)*XUSER_MAX_COUNT); + +#ifdef __ORBIS__ + m_hBGMAudio=GetAudioBGMHandle(); +#endif +} + +void SoundEngine::destroy() {} + +#ifdef _DEBUG +void SoundEngine::GetSoundName(char *szSoundName,int iSound) +{ + strcpy((char *)szSoundName,"Minecraft/"); + wstring name = wchSoundNames[iSound]; + char *SoundName = (char *)ConvertSoundPathToName(name); + strcat((char *)szSoundName,SoundName); +} +#endif + +///////////////////////////////////////////// +// +// play +// +///////////////////////////////////////////// +void SoundEngine::play(int iSound, float x, float y, float z, float volume, float pitch) +{ + U8 szSoundName[256]; + + if(iSound==-1) + { + app.DebugPrintf(6,"PlaySound with sound of -1 !!!!!!!!!!!!!!!\n"); + return; + } + + // AP removed old counting system. Now relying on Miles' Play Count Limit + /* // if we are already playing loads of this sounds ignore this one + if(CurrentSoundsPlaying[iSound+eSFX_MAX]>MAX_SAME_SOUNDS_PLAYING) + { + // wstring name = wchSoundNames[iSound]; + // char *SoundName = (char *)ConvertSoundPathToName(name); + // app.DebugPrintf("Too many %s sounds playing!\n",SoundName); + return; + }*/ + + //if (iSound != eSoundType_MOB_IRONGOLEM_WALK) return; + + // build the name + strcpy((char *)szSoundName,"Minecraft/"); + +#ifdef DISTORTION_TEST + wstring name = wchSoundNames[eSoundType_MOB_ENDERDRAGON_GROWL]; +#else + wstring name = wchSoundNames[iSound]; +#endif + + char *SoundName = (char *)ConvertSoundPathToName(name); + strcat((char *)szSoundName,SoundName); + +// app.DebugPrintf(6,"PlaySound - %d - %s - %s (%f %f %f, vol %f, pitch %f)\n",iSound, SoundName, szSoundName,x,y,z,volume,pitch); + + AUDIO_INFO AudioInfo; + AudioInfo.x=x; + AudioInfo.y=y; + AudioInfo.z=z; + AudioInfo.volume=volume; + AudioInfo.pitch=pitch; + AudioInfo.bIs3D=true; + AudioInfo.bUseSoundsPitchVal=false; + AudioInfo.iSound=iSound+eSFX_MAX; +#ifdef _DEBUG + strncpy(AudioInfo.chName,(char *)szSoundName,64); +#endif + + S32 token = AIL_enqueue_event_start(); + AIL_enqueue_event_buffer(&token, &AudioInfo, sizeof(AUDIO_INFO), 0); + AIL_enqueue_event_end_named(token, (char *)szSoundName); +} + +///////////////////////////////////////////// +// +// playUI +// +///////////////////////////////////////////// +void SoundEngine::playUI(int iSound, float volume, float pitch) +{ + U8 szSoundName[256]; + wstring name; + // we have some game sounds played as UI sounds... + // Not the best way to do this, but it seems to only be the portal sounds + + if(iSound>=eSFX_MAX) + { + // AP removed old counting system. Now relying on Miles' Play Count Limit + /* // if we are already playing loads of this sounds ignore this one + if(CurrentSoundsPlaying[iSound+eSFX_MAX]>MAX_SAME_SOUNDS_PLAYING) return;*/ + + // build the name + strcpy((char *)szSoundName,"Minecraft/"); + name = wchSoundNames[iSound]; + } + else + { + // AP removed old counting system. Now relying on Miles' Play Count Limit + /* // if we are already playing loads of this sounds ignore this one + if(CurrentSoundsPlaying[iSound]>MAX_SAME_SOUNDS_PLAYING) return;*/ + + // build the name + strcpy((char *)szSoundName,"Minecraft/UI/"); + name = wchUISoundNames[iSound]; + } + + char *SoundName = (char *)ConvertSoundPathToName(name); + strcat((char *)szSoundName,SoundName); +// app.DebugPrintf("UI: Playing %s, volume %f, pitch %f\n",SoundName,volume,pitch); + + //app.DebugPrintf("PlaySound - %d - %s\n",iSound, SoundName); + + AUDIO_INFO AudioInfo; + memset(&AudioInfo,0,sizeof(AUDIO_INFO)); + AudioInfo.volume=volume; // will be multiplied by the master volume + AudioInfo.pitch=pitch; + AudioInfo.bUseSoundsPitchVal=true; + if(iSound>=eSFX_MAX) + { + AudioInfo.iSound=iSound+eSFX_MAX; + } + else + { + AudioInfo.iSound=iSound; + } +#ifdef _DEBUG + strncpy(AudioInfo.chName,(char *)szSoundName,64); +#endif + + // 4J-PB - not going to stop UI events happening based on the number of currently playing sounds + S32 token = AIL_enqueue_event_start(); + AIL_enqueue_event_buffer(&token, &AudioInfo, sizeof(AUDIO_INFO), 0); + AIL_enqueue_event_end_named(token, (char *)szSoundName); +} + +///////////////////////////////////////////// +// +// playStreaming +// +///////////////////////////////////////////// +void SoundEngine::playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay) +{ + // This function doesn't actually play a streaming sound, just sets states and an id for the music tick to play it + // Level audio will be played when a play with an empty name comes in + // CD audio will be played when a named stream comes in + + m_StreamingAudioInfo.x=x; + m_StreamingAudioInfo.y=y; + m_StreamingAudioInfo.z=z; + m_StreamingAudioInfo.volume=volume; + m_StreamingAudioInfo.pitch=pitch; + + if(m_StreamState==eMusicStreamState_Playing) + { + m_StreamState=eMusicStreamState_Stop; + } + else if(m_StreamState==eMusicStreamState_Opening) + { + m_StreamState=eMusicStreamState_OpeningCancel; + } + + if(name.empty()) + { + // music, or stop CD + m_StreamingAudioInfo.bIs3D=false; + + // we need a music id + // random delay of up to 3 minutes for music + m_iMusicDelay = random->nextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10; + +#ifdef _DEBUG + m_iMusicDelay=0; +#endif + Minecraft *pMinecraft=Minecraft::GetInstance(); + + bool playerInEnd=false; + bool playerInNether=false; + + for(unsigned int i=0;ilocalplayers[i]!=NULL) + { + if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END) + { + playerInEnd=true; + } + else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER) + { + playerInNether=true; + } + } + } + if(playerInEnd) + { + m_musicID = getMusicID(LevelData::DIMENSION_END); + } + else if(playerInNether) + { + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + } + else + { + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + } + } + else + { + // jukebox + m_StreamingAudioInfo.bIs3D=true; + m_musicID=getMusicID(name); + m_iMusicDelay=0; + } +} + + +int SoundEngine::GetRandomishTrack(int iStart,int iEnd) +{ + // 4J-PB - make it more likely that we'll get a track we've not heard for a while, although repeating tracks sometimes is fine + + // if all tracks have been heard, clear the flags + bool bAllTracksHeard=true; + int iVal=iStart; + for(int i=iStart;i<=iEnd;i++) + { + if(m_bHeardTrackA[i]==false) + { + bAllTracksHeard=false; + app.DebugPrintf("Not heard all tracks yet\n"); + break; + } + } + + if(bAllTracksHeard) + { + app.DebugPrintf("Heard all tracks - resetting the tracking array\n"); + + for(int i=iStart;i<=iEnd;i++) + { + m_bHeardTrackA[i]=false; + } + } + + // trying to get a track we haven't heard, but not too hard + for(int i=0;i<=((iEnd-iStart)/2);i++) + { + // random->nextInt(1) will always return 0 + iVal=random->nextInt((iEnd-iStart)+1)+iStart; + if(m_bHeardTrackA[iVal]==false) + { + // not heard this + app.DebugPrintf("(%d) Not heard track %d yet, so playing it now\n",i,iVal); + m_bHeardTrackA[iVal]=true; + break; + } + else + { + app.DebugPrintf("(%d) Skipping track %d already heard it recently\n",i,iVal); + } + } + + app.DebugPrintf("Select track %d\n",iVal); + return iVal; +} +///////////////////////////////////////////// +// +// getMusicID +// +///////////////////////////////////////////// +int SoundEngine::getMusicID(int iDomain) +{ + int iRandomVal=0; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // Before the game has started? + if(pMinecraft==NULL) + { + // any track from the overworld + return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); + } + + if(pMinecraft->skins->isUsingDefaultSkin()) + { + switch(iDomain) + { + case LevelData::DIMENSION_END: + // the end isn't random - it has different music depending on whether the dragon is alive or not, but we've not added the dead dragon music yet + return m_iStream_End_Min; + case LevelData::DIMENSION_NETHER: + return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max); + //return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min); + default: //overworld + //return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min); + return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); + } + } + else + { + // using a texture pack - may have multiple End music tracks + switch(iDomain) + { + case LevelData::DIMENSION_END: + return GetRandomishTrack(m_iStream_End_Min,m_iStream_End_Max); + case LevelData::DIMENSION_NETHER: + //return m_iStream_Nether_Min + random->nextInt(m_iStream_Nether_Max-m_iStream_Nether_Min); + return GetRandomishTrack(m_iStream_Nether_Min,m_iStream_Nether_Max); + default: //overworld + //return m_iStream_Overworld_Min + random->nextInt(m_iStream_Overworld_Max-m_iStream_Overworld_Min); + return GetRandomishTrack(m_iStream_Overworld_Min,m_iStream_Overworld_Max); + } + } +} + +///////////////////////////////////////////// +// +// getMusicID +// +///////////////////////////////////////////// +// check what the CD is +int SoundEngine::getMusicID(const wstring& name) +{ + int iCD=0; + char *SoundName = (char *)ConvertSoundPathToName(name,true); + + // 4J-PB - these will always be the game cds, so use the m_szStreamFileA for this + for(int i=0;i<12;i++) + { + if(strcmp(SoundName,m_szStreamFileA[i+eStream_CD_1])==0) + { + iCD=i; + break; + } + } + + // adjust for cd start position on normal or mash-up pack + return iCD+m_iStream_CD_1; +} + +///////////////////////////////////////////// +// +// getMasterMusicVolume +// +///////////////////////////////////////////// +float SoundEngine::getMasterMusicVolume() +{ + if( m_bSystemMusicPlaying ) + { + return 0.0f; + } + else + { + return m_MasterMusicVolume; + } +} + +///////////////////////////////////////////// +// +// updateMusicVolume +// +///////////////////////////////////////////// +void SoundEngine::updateMusicVolume(float fVal) +{ + m_MasterMusicVolume=fVal; +} + +///////////////////////////////////////////// +// +// updateSystemMusicPlaying +// +///////////////////////////////////////////// +void SoundEngine::updateSystemMusicPlaying(bool isPlaying) +{ + m_bSystemMusicPlaying = isPlaying; +} + +///////////////////////////////////////////// +// +// updateSoundEffectVolume +// +///////////////////////////////////////////// +void SoundEngine::updateSoundEffectVolume(float fVal) +{ + m_MasterEffectsVolume=fVal; + //AIL_set_variable_float(0,"UserEffectVol",fVal); +} + +void SoundEngine::add(const wstring& name, File *file) {} +void SoundEngine::addMusic(const wstring& name, File *file) {} +void SoundEngine::addStreaming(const wstring& name, File *file) {} +bool SoundEngine::isStreamingWavebankReady() { return true; } + +int SoundEngine::OpenStreamThreadProc( void* lpParameter ) +{ +#ifdef __DISABLE_MILES__ + return 0; +#endif + SoundEngine *soundEngine = (SoundEngine *)lpParameter; + soundEngine->m_hStream = AIL_open_stream(soundEngine->m_hDriver,soundEngine->m_szStreamName,0); + return 0; +} + +///////////////////////////////////////////// +// +// playMusicTick +// +///////////////////////////////////////////// +void SoundEngine::playMusicTick() +{ +// AP - vita will update the music during the mixer callback +#ifndef __PSVITA__ + playMusicUpdate(); +#endif +} + +// AP - moved to a separate function so it can be called from the mixer callback on Vita +void SoundEngine::playMusicUpdate() +{ + //return; + static bool firstCall = true; + static float fMusicVol = 0.0f; + if( firstCall ) + { + fMusicVol = getMasterMusicVolume(); + firstCall = false; + } + + switch(m_StreamState) + { + case eMusicStreamState_Idle: + + // start a stream playing + if (m_iMusicDelay > 0) + { + m_iMusicDelay--; + return; + } + + if(m_musicID!=-1) + { + // start playing it + + +#if ( defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ ) + +#ifdef __PS3__ + // 4J-PB - Need to check if we are a patched BD build + if(app.GetBootedFromDiscPatch()) + { + sprintf(m_szStreamName,"%s/%s",app.GetBDUsrDirPath(m_szMusicPath), m_szMusicPath ); + app.DebugPrintf("SoundEngine::playMusicUpdate - (booted from disc patch) music path - %s",m_szStreamName); + } + else + { + sprintf(m_szStreamName,"%s/%s",getUsrDirPath(), m_szMusicPath ); + } +#else + sprintf(m_szStreamName,"%s/%s",getUsrDirPath(), m_szMusicPath ); +#endif + +#else + strcpy((char *)m_szStreamName,m_szMusicPath); +#endif + // are we using a mash-up pack? + //if(pMinecraft && !pMinecraft->skins->isUsingDefaultSkin() && pMinecraft->skins->getSelected()->hasAudio()) + if(Minecraft::GetInstance()->skins->getSelected()->hasAudio()) + { + // It's a mash-up - need to use the DLC path for the music + TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)pTexPack; + DLCPack *pack = pDLCTexPack->getDLCInfoParentPack(); + DLCAudioFile *dlcAudioFile = (DLCAudioFile *) pack->getFile(DLCManager::e_DLCType_Audio, 0); + + app.DebugPrintf("Mashup pack \n"); + + // build the name + + // if the music ID is beyond the end of the texture pack music files, then it's a CD + if(m_musicIDGetSoundName(m_musicID); + wstring wstrFile=L"TPACK:\\Data\\" + wstrSoundName +L".binka"; + std::wstring mountedPath = StorageManager.GetMountedPath(wstrFile); + wcstombs(m_szStreamName,mountedPath.c_str(),255); +#else + wstring &wstrSoundName=dlcAudioFile->GetSoundName(m_musicID); + char szName[255]; + wcstombs(szName,wstrSoundName.c_str(),255); + + string strFile="TPACK:\\Data\\" + string(szName) + ".binka"; + std::string mountedPath = StorageManager.GetMountedPath(strFile); + strcpy(m_szStreamName,mountedPath.c_str()); +#endif + } + else + { + SetIsPlayingStreamingGameMusic(false); + SetIsPlayingStreamingCDMusic(true); + m_MusicType=eMusicType_CD; + m_StreamingAudioInfo.bIs3D=true; + + // Need to adjust to index into the cds in the game's m_szStreamFileA + strcat((char *)m_szStreamName,"cds/"); + strcat((char *)m_szStreamName,m_szStreamFileA[m_musicID-m_iStream_CD_1+eStream_CD_1]); + strcat((char *)m_szStreamName,".binka"); + } + } + else + { + // 4J-PB - if this is a PS3 disc patch, we have to check if the music file is in the patch data +#ifdef __PS3__ + if(app.GetBootedFromDiscPatch() && (m_musicIDRun(); + m_StreamState = eMusicStreamState_Opening; + } + break; + + case eMusicStreamState_Opening: + // If the open stream thread is complete, then we are ready to proceed to actually playing + if( !m_openStreamThread->isRunning() ) + { + delete m_openStreamThread; + m_openStreamThread = NULL; + + HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); + + // 4J-PB - causes the falloff to be calculated on the PPU instead of the SPU, and seems to resolve our distorted sound issue + AIL_register_falloff_function_callback(hSample,&custom_falloff_function); + + if(m_StreamingAudioInfo.bIs3D) + { + AIL_set_sample_3D_distances(hSample,64.0f,1,0); // Larger distance scaler for music discs + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-m_StreamingAudioInfo.x); + y=fabs(m_ListenerA[i].vPosition.y-m_StreamingAudioInfo.y); + z=fabs(m_ListenerA[i].vPosition.z-m_StreamingAudioInfo.z); + fDist=x+y+z; + + if(fDistisRunning() ) + { + delete m_openStreamThread; + m_openStreamThread = NULL; + m_StreamState = eMusicStreamState_Stop; + } + break; + case eMusicStreamState_Stop: + // should gradually take the volume down in steps + AIL_pause_stream(m_hStream,1); + AIL_close_stream(m_hStream); + m_hStream=0; + SetIsPlayingStreamingCDMusic(false); + SetIsPlayingStreamingGameMusic(false); + m_StreamState=eMusicStreamState_Idle; + break; + case eMusicStreamState_Stopping: + break; + case eMusicStreamState_Play: + break; + case eMusicStreamState_Playing: + if(GetIsPlayingStreamingGameMusic()) + { + //if(m_MusicInfo.pCue!=NULL) + { + bool playerInEnd = false; + bool playerInNether=false; + Minecraft *pMinecraft = Minecraft::GetInstance(); + for(unsigned int i = 0; i < MAX_LOCAL_PLAYERS; ++i) + { + if(pMinecraft->localplayers[i]!=NULL) + { + if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END) + { + playerInEnd=true; + } + else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER) + { + playerInNether=true; + } + } + } + + if(playerInEnd && !GetIsPlayingEndMusic()) + { + m_StreamState=eMusicStreamState_Stop; + + // Set the end track + m_musicID = getMusicID(LevelData::DIMENSION_END); + SetIsPlayingEndMusic(true); + SetIsPlayingNetherMusic(false); + } + else if(!playerInEnd && GetIsPlayingEndMusic()) + { + if(playerInNether) + { + m_StreamState=eMusicStreamState_Stop; + + // Set the end track + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + SetIsPlayingEndMusic(false); + SetIsPlayingNetherMusic(true); + } + else + { + m_StreamState=eMusicStreamState_Stop; + + // Set the end track + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + SetIsPlayingEndMusic(false); + SetIsPlayingNetherMusic(false); + } + } + else if (playerInNether && !GetIsPlayingNetherMusic()) + { + m_StreamState=eMusicStreamState_Stop; + // set the Nether track + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + SetIsPlayingNetherMusic(true); + SetIsPlayingEndMusic(false); + } + else if(!playerInNether && GetIsPlayingNetherMusic()) + { + if(playerInEnd) + { + m_StreamState=eMusicStreamState_Stop; + // set the Nether track + m_musicID = getMusicID(LevelData::DIMENSION_END); + SetIsPlayingNetherMusic(false); + SetIsPlayingEndMusic(true); + } + else + { + m_StreamState=eMusicStreamState_Stop; + // set the Nether track + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + SetIsPlayingNetherMusic(false); + SetIsPlayingEndMusic(false); + } + } + + // volume change required? + if(fMusicVol!=getMasterMusicVolume()) + { + fMusicVol=getMasterMusicVolume(); + HSAMPLE hSample = AIL_stream_sample_handle( m_hStream); + //AIL_set_sample_3D_position( hSample, m_StreamingAudioInfo.x, m_StreamingAudioInfo.y, m_StreamingAudioInfo.z ); + AIL_set_sample_volume_levels( hSample, fMusicVol, fMusicVol); + } + } + } + else + { + // Music disc playing - if it's a 3D stream, then set the position - we don't have any streaming audio in the world that moves, so this isn't + // required unless we have more than one listener, and are setting the listening position to the origin and setting a fake position + // for the sound down the z axis + if(m_StreamingAudioInfo.bIs3D) + { + if(m_validListenerCount>1) + { + float fClosest=10000.0f; + int iClosestListener=0; + float fClosestX=0.0f,fClosestY=0.0f,fClosestZ=0.0f,fDist; + + // need to calculate the distance from the sound to the nearest listener - use Manhattan Distance as the decision + for( int i = 0; i < MAX_LOCAL_PLAYERS; i++ ) + { + if( m_ListenerA[i].bValid ) + { + float x,y,z; + + x=fabs(m_ListenerA[i].vPosition.x-m_StreamingAudioInfo.x); + y=fabs(m_ListenerA[i].vPosition.y-m_StreamingAudioInfo.y); + z=fabs(m_ListenerA[i].vPosition.z-m_StreamingAudioInfo.z); + fDist=x+y+z; + + if(fDistnextInt(20 * 60 * 3);//random->nextInt(20 * 60 * 10) + 20 * 60 * 10; + // Check if we have a local player in The Nether or in The End, and play that music if they are + Minecraft *pMinecraft=Minecraft::GetInstance(); + bool playerInEnd=false; + bool playerInNether=false; + + for(unsigned int i=0;ilocalplayers[i]!=NULL) + { + if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_END) + { + playerInEnd=true; + } + else if(pMinecraft->localplayers[i]->dimension==LevelData::DIMENSION_NETHER) + { + playerInNether=true; + } + } + } + if(playerInEnd) + { + m_musicID = getMusicID(LevelData::DIMENSION_END); + SetIsPlayingEndMusic(true); + SetIsPlayingNetherMusic(false); + } + else if(playerInNether) + { + m_musicID = getMusicID(LevelData::DIMENSION_NETHER); + SetIsPlayingNetherMusic(true); + SetIsPlayingEndMusic(false); + } + else + { + m_musicID = getMusicID(LevelData::DIMENSION_OVERWORLD); + SetIsPlayingNetherMusic(false); + SetIsPlayingEndMusic(false); + } + + m_StreamState=eMusicStreamState_Idle; + } + break; + } + + // check the status of the stream - this is for when a track completes rather than is stopped by the user action + + if(m_hStream!=0) + { + if(AIL_stream_status(m_hStream)==SMP_DONE ) // SMP_DONE + { + AIL_close_stream(m_hStream); + m_hStream=0; + SetIsPlayingStreamingCDMusic(false); + SetIsPlayingStreamingGameMusic(false); + + m_StreamState=eMusicStreamState_Completed; + } + } +} + + +///////////////////////////////////////////// +// +// ConvertSoundPathToName +// +///////////////////////////////////////////// +char *SoundEngine::ConvertSoundPathToName(const wstring& name, bool bConvertSpaces) +{ + static char buf[256]; + assert(name.length()<256); + for(unsigned int i = 0; i < name.length(); i++ ) + { + wchar_t c = name[i]; + if(c=='.') c='/'; + if(bConvertSpaces) + { + if(c==' ') c='_'; + } + buf[i] = (char)c; + } + buf[name.length()] = 0; + return buf; +} + +#endif + + +F32 AILCALLBACK custom_falloff_function (HSAMPLE S, + F32 distance, + F32 rolloff_factor, + F32 min_dist, + F32 max_dist) +{ + F32 result; + + // This is now emulating the linear fall-off function that we used on the Xbox 360. The parameter which is passed as "max_dist" is the only one actually used, + // and is generally used as CurveDistanceScaler is used on XACT on the Xbox. A special value of 10000.0f is passed for thunder, which has no attenuation + + if( max_dist == 10000.0f ) + { + return 1.0f; + } + + result = 1.0f - ( distance / max_dist ); + if( result < 0.0f ) result = 0.0f; + if( result > 1.0f ) result = 1.0f; + + return result; +} diff --git a/Minecraft.Client/Common/Audio/SoundEngine.h b/Minecraft.Client/Common/Audio/SoundEngine.h new file mode 100644 index 0000000..92c99d2 --- /dev/null +++ b/Minecraft.Client/Common/Audio/SoundEngine.h @@ -0,0 +1,168 @@ +#pragma once +class Mob; +class Options; +using namespace std; +#include "..\..\Minecraft.World\SoundTypes.h" + +enum eMUSICFILES +{ + eStream_Overworld_Calm1 = 0, + eStream_Overworld_Calm2, + eStream_Overworld_Calm3, + eStream_Overworld_hal1, + eStream_Overworld_hal2, + eStream_Overworld_hal3, + eStream_Overworld_hal4, + eStream_Overworld_nuance1, + eStream_Overworld_nuance2, +#ifndef _XBOX + // Add the new music tracks + eStream_Overworld_Creative1, + eStream_Overworld_Creative2, + eStream_Overworld_Creative3, + eStream_Overworld_Creative4, + eStream_Overworld_Creative5, + eStream_Overworld_Creative6, + eStream_Overworld_Menu1, + eStream_Overworld_Menu2, + eStream_Overworld_Menu3, + eStream_Overworld_Menu4, +#endif + eStream_Overworld_piano1, + eStream_Overworld_piano2, + eStream_Overworld_piano3, // <-- make piano3 the last overworld one + // Nether + eStream_Nether1, + eStream_Nether2, + eStream_Nether3, + eStream_Nether4, + // The End + eStream_end_dragon, + eStream_end_end, + eStream_CD_1, + eStream_CD_2, + eStream_CD_3, + eStream_CD_4, + eStream_CD_5, + eStream_CD_6, + eStream_CD_7, + eStream_CD_8, + eStream_CD_9, + eStream_CD_10, + eStream_CD_11, + eStream_CD_12, + eStream_Max, +}; + +enum eMUSICTYPE +{ + eMusicType_None, + eMusicType_Game, + eMusicType_CD, +}; + + +enum MUSIC_STREAMSTATE +{ + eMusicStreamState_Idle=0, + eMusicStreamState_Stop, + eMusicStreamState_Stopping, + eMusicStreamState_Opening, + eMusicStreamState_OpeningCancel, + eMusicStreamState_Play, + eMusicStreamState_Playing, + eMusicStreamState_Completed +}; + +typedef struct +{ + F32 x,y,z,volume,pitch; + int iSound; + bool bIs3D; + bool bUseSoundsPitchVal; +#ifdef _DEBUG + char chName[64]; +#endif +} +AUDIO_INFO; + +class SoundEngine : public ConsoleSoundEngine +{ + static const int MAX_SAME_SOUNDS_PLAYING = 8; // 4J added +public: + SoundEngine(); + virtual void destroy(); +#ifdef _DEBUG + void GetSoundName(char *szSoundName,int iSound); +#endif + virtual void play(int iSound, float x, float y, float z, float volume, float pitch); + virtual void playStreaming(const wstring& name, float x, float y , float z, float volume, float pitch, bool bMusicDelay=true); + virtual void playUI(int iSound, float volume, float pitch); + virtual void playMusicTick(); + virtual void updateMusicVolume(float fVal); + virtual void updateSystemMusicPlaying(bool isPlaying); + virtual void updateSoundEffectVolume(float fVal); + virtual void init(Options *); + virtual void tick(shared_ptr *players, float a); // 4J - updated to take array of local players rather than single one + virtual void add(const wstring& name, File *file); + virtual void addMusic(const wstring& name, File *file); + virtual void addStreaming(const wstring& name, File *file); + virtual char *ConvertSoundPathToName(const wstring& name, bool bConvertSpaces=false); + bool isStreamingWavebankReady(); // 4J Added + int getMusicID(int iDomain); + int getMusicID(const wstring& name); + void SetStreamingSounds(int iOverworldMin, int iOverWorldMax, int iNetherMin, int iNetherMax, int iEndMin, int iEndMax, int iCD1); + void updateMiles(); // AP added so Vita can update all the Miles functions during the mixer callback + void playMusicUpdate(); + +private: + float getMasterMusicVolume(); + // platform specific functions +#ifdef __PS3__ + int initAudioHardware(int iMinSpeakers); +#else + int initAudioHardware(int iMinSpeakers) { return iMinSpeakers;} +#endif + + int GetRandomishTrack(int iStart,int iEnd); + + HMSOUNDBANK m_hBank; + HDIGDRIVER m_hDriver; + HSTREAM m_hStream; + + static char m_szSoundPath[]; + static char m_szMusicPath[]; + static char m_szRedistName[]; + static char *m_szStreamFileA[eStream_Max]; + + AUDIO_LISTENER m_ListenerA[MAX_LOCAL_PLAYERS]; + int m_validListenerCount; + + + Random *random; + int m_musicID; + int m_iMusicDelay; + int m_StreamState; + int m_MusicType; + AUDIO_INFO m_StreamingAudioInfo; + wstring m_CDMusic; + BOOL m_bSystemMusicPlaying; + float m_MasterMusicVolume; + float m_MasterEffectsVolume; + + C4JThread *m_openStreamThread; + static int OpenStreamThreadProc( void* lpParameter ); + char m_szStreamName[255]; + int CurrentSoundsPlaying[eSoundType_MAX+eSFX_MAX]; + + // streaming music files - will be different for mash-up packs + int m_iStream_Overworld_Min,m_iStream_Overworld_Max; + int m_iStream_Nether_Min,m_iStream_Nether_Max; + int m_iStream_End_Min,m_iStream_End_Max; + int m_iStream_CD_1; + bool *m_bHeardTrackA; + +#ifdef __ORBIS__ + int32_t m_hBGMAudio; +#endif +}; diff --git a/Minecraft.Client/Common/Audio/SoundNames.cpp b/Minecraft.Client/Common/Audio/SoundNames.cpp new file mode 100644 index 0000000..170c87a --- /dev/null +++ b/Minecraft.Client/Common/Audio/SoundNames.cpp @@ -0,0 +1,165 @@ +#include "stdafx.h" + +#include "Consoles_SoundEngine.h" + + + +const WCHAR *ConsoleSoundEngine::wchSoundNames[eSoundType_MAX]= +{ + L"mob.chicken", // eSoundType_MOB_CHICKEN_AMBIENT + L"mob.chickenhurt", // eSoundType_MOB_CHICKEN_HURT + L"mob.chickenplop", // eSoundType_MOB_CHICKENPLOP + L"mob.cow", // eSoundType_MOB_COW_AMBIENT + L"mob.cowhurt", // eSoundType_MOB_COW_HURT + L"mob.pig", // eSoundType_MOB_PIG_AMBIENT + L"mob.pigdeath", // eSoundType_MOB_PIG_DEATH + L"mob.sheep", // eSoundType_MOB_SHEEP_AMBIENT + L"mob.wolf.growl", // eSoundType_MOB_WOLF_GROWL + L"mob.wolf.whine", // eSoundType_MOB_WOLF_WHINE + L"mob.wolf.panting", // eSoundType_MOB_WOLF_PANTING + L"mob.wolf.bark", // eSoundType_MOB_WOLF_BARK + L"mob.wolf.hurt", // eSoundType_MOB_WOLF_HURT + L"mob.wolf.death", // eSoundType_MOB_WOLF_DEATH + L"mob.wolf.shake", // eSoundType_MOB_WOLF_SHAKE + L"mob.blaze.breathe", // eSoundType_MOB_BLAZE_BREATHE + L"mob.blaze.hit", // eSoundType_MOB_BLAZE_HURT + L"mob.blaze.death", // eSoundType_MOB_BLAZE_DEATH + L"mob.ghast.moan", // eSoundType_MOB_GHAST_MOAN + L"mob.ghast.scream", // eSoundType_MOB_GHAST_SCREAM + L"mob.ghast.death", // eSoundType_MOB_GHAST_DEATH + L"mob.ghast.fireball", // eSoundType_MOB_GHAST_FIREBALL + L"mob.ghast.charge", // eSoundType_MOB_GHAST_CHARGE + L"mob.endermen.idle", // eSoundType_MOB_ENDERMEN_IDLE + L"mob.endermen.hit", // eSoundType_MOB_ENDERMEN_HIT + L"mob.endermen.death", // eSoundType_MOB_ENDERMEN_DEATH + L"mob.endermen.portal", // eSoundType_MOB_ENDERMEN_PORTAL + L"mob.zombiepig.zpig", // eSoundType_MOB_ZOMBIEPIG_AMBIENT + L"mob.zombiepig.zpighurt", // eSoundType_MOB_ZOMBIEPIG_HURT + L"mob.zombiepig.zpigdeath", // eSoundType_MOB_ZOMBIEPIG_DEATH + L"mob.zombiepig.zpigangry", // eSoundType_MOB_ZOMBIEPIG_ZPIGANGRY + L"mob.silverfish.say", // eSoundType_MOB_SILVERFISH_AMBIENT, + L"mob.silverfish.hit", // eSoundType_MOB_SILVERFISH_HURT + L"mob.silverfish.kill", // eSoundType_MOB_SILVERFISH_DEATH, + L"mob.silverfish.step", // eSoundType_MOB_SILVERFISH_STEP, + L"mob.skeleton", // eSoundType_MOB_SKELETON_AMBIENT, + L"mob.skeletonhurt", // eSoundType_MOB_SKELETON_HURT, + L"mob.spider", // eSoundType_MOB_SPIDER_AMBIENT, + L"mob.spiderdeath", // eSoundType_MOB_SPIDER_DEATH, + L"mob.slime", // eSoundType_MOB_SLIME, + L"mob.slimeattack", // eSoundType_MOB_SLIME_ATTACK, + L"mob.creeper", // eSoundType_MOB_CREEPER_HURT, + L"mob.creeperdeath", // eSoundType_MOB_CREEPER_DEATH, + L"mob.zombie", // eSoundType_MOB_ZOMBIE_AMBIENT, + L"mob.zombiehurt", // eSoundType_MOB_ZOMBIE_HURT, + L"mob.zombiedeath", // eSoundType_MOB_ZOMBIE_DEATH, + L"mob.zombie.wood", // eSoundType_MOB_ZOMBIE_WOOD, + L"mob.zombie.woodbreak", // eSoundType_MOB_ZOMBIE_WOOD_BREAK, + L"mob.zombie.metal", // eSoundType_MOB_ZOMBIE_METAL, + L"mob.magmacube.big", // eSoundType_MOB_MAGMACUBE_BIG, + L"mob.magmacube.small", // eSoundType_MOB_MAGMACUBE_SMALL, + L"mob.cat.purr", // eSoundType_MOB_CAT_PURR + L"mob.cat.purreow", // eSoundType_MOB_CAT_PURREOW + L"mob.cat.meow", // eSoundType_MOB_CAT_MEOW + // 4J-PB - correct the name of the event for hitting ocelots + L"mob.cat.hit", // eSoundType_MOB_CAT_HITT +// L"mob.irongolem.throw", // eSoundType_MOB_IRONGOLEM_THROW +// L"mob.irongolem.hit", // eSoundType_MOB_IRONGOLEM_HIT +// L"mob.irongolem.death", // eSoundType_MOB_IRONGOLEM_DEATH +// L"mob.irongolem.walk", // eSoundType_MOB_IRONGOLEM_WALK + L"random.bow", // eSoundType_RANDOM_BOW, + L"random.bowhit", // eSoundType_RANDOM_BOW_HIT, + L"random.explode", // eSoundType_RANDOM_EXPLODE, + L"random.fizz", // eSoundType_RANDOM_FIZZ, + L"random.pop", // eSoundType_RANDOM_POP, + L"random.fuse", // eSoundType_RANDOM_FUSE, + L"random.drink", // eSoundType_RANDOM_DRINK, + L"random.eat", // eSoundType_RANDOM_EAT, + L"random.burp", // eSoundType_RANDOM_BURP, + L"random.splash", // eSoundType_RANDOM_SPLASH, + L"random.click", // eSoundType_RANDOM_CLICK, + L"random.glass", // eSoundType_RANDOM_GLASS, + L"random.orb", // eSoundType_RANDOM_ORB, + L"random.break", // eSoundType_RANDOM_BREAK, + L"random.chestopen", // eSoundType_RANDOM_CHEST_OPEN, + L"random.chestclosed", // eSoundType_RANDOM_CHEST_CLOSE, + L"random.door_open", // eSoundType_RANDOM_DOOR_OPEN, + L"random.door_close", // eSoundType_RANDOM_DOOR_CLOSE, + L"ambient.weather.rain", // eSoundType_AMBIENT_WEATHER_RAIN, + L"ambient.weather.thunder", // eSoundType_AMBIENT_WEATHER_THUNDER, + L"ambient.cave.cave", // eSoundType_CAVE_CAVE, DON'T USE FOR XBOX 360!!! +#ifdef _XBOX + L"ambient.cave.cave2", // eSoundType_CAVE_CAVE2 - removed the two sounds that were at 192k in the first ambient cave event +#endif + L"portal.portal", // eSoundType_PORTAL_PORTAL, + // 4J-PB - added a couple that were still using wstring + L"portal.trigger", // eSoundType_PORTAL_TRIGGER + L"portal.travel", // eSoundType_PORTAL_TRAVEL + + L"fire.ignite", // eSoundType_FIRE_IGNITE, + L"fire.fire", // eSoundType_FIRE_FIRE, + L"damage.hurtflesh", // eSoundType_DAMAGE_HURT, + L"damage.fallsmall", // eSoundType_DAMAGE_FALL_SMALL, + L"damage.fallbig", // eSoundType_DAMAGE_FALL_BIG, + L"note.harp", // eSoundType_NOTE_HARP, + L"note.bd", // eSoundType_NOTE_BD, + L"note.snare", // eSoundType_NOTE_SNARE, + L"note.hat", // eSoundType_NOTE_HAT, + L"note.bassattack", // eSoundType_NOTE_BASSATTACK, + L"tile.piston.in", // eSoundType_TILE_PISTON_IN, + L"tile.piston.out", // eSoundType_TILE_PISTON_OUT, + L"liquid.water", // eSoundType_LIQUID_WATER, + L"liquid.lavapop", // eSoundType_LIQUID_LAVA_POP, + L"liquid.lava", // eSoundType_LIQUID_LAVA, + L"step.stone", // eSoundType_STEP_STONE, + L"step.wood", // eSoundType_STEP_WOOD, + L"step.gravel", // eSoundType_STEP_GRAVEL, + L"step.grass", // eSoundType_STEP_GRASS, + L"step.metal", // eSoundType_STEP_METAL, + L"step.cloth", // eSoundType_STEP_CLOTH, + L"step.sand", // eSoundType_STEP_SAND, + + // below this are the additional sounds from the second soundbank + L"mob.enderdragon.end", // eSoundType_MOB_ENDERDRAGON_END + L"mob.enderdragon.growl", // eSoundType_MOB_ENDERDRAGON_GROWL + L"mob.enderdragon.hit", // eSoundType_MOB_ENDERDRAGON_HIT + L"mob.enderdragon.wings", // eSoundType_MOB_ENDERDRAGON_MOVE + L"mob.irongolem.throw", // eSoundType_MOB_IRONGOLEM_THROW + L"mob.irongolem.hit", // eSoundType_MOB_IRONGOLEM_HIT + L"mob.irongolem.death", // eSoundType_MOB_IRONGOLEM_DEATH + L"mob.irongolem.walk", // eSoundType_MOB_IRONGOLEM_WALK + + // TU14 + L"damage.thorns", // eSoundType_DAMAGE_THORNS + L"random.anvil_break", // eSoundType_RANDOM_ANVIL_BREAK + L"random.anvil_land", // eSoundType_RANDOM_ANVIL_LAND + L"random.anvil_use", // eSoundType_RANDOM_ANVIL_USE + L"mob.villager.haggle", // eSoundType_MOB_VILLAGER_HAGGLE + L"mob.villager.idle", // eSoundType_MOB_VILLAGER_IDLE + L"mob.villager.hit", // eSoundType_MOB_VILLAGER_HIT + L"mob.villager.death", // eSoundType_MOB_VILLAGER_DEATH + L"mob.villager.yes", // eSoundType_MOB_VILLAGER_YES + L"mob.villager.no", // eSoundType_MOB_VILLAGER_NO + L"mob.zombie.infect", // eSoundType_MOB_ZOMBIE_INFECT + L"mob.zombie.unfect", // eSoundType_MOB_ZOMBIE_UNFECT + L"mob.zombie.remedy", // eSoundType_MOB_ZOMBIE_REMEDY + L"step.snow", // eSoundType_STEP_SNOW + L"step.ladder", // eSoundType_STEP_LADDER + L"dig.cloth", // eSoundType_DIG_CLOTH + L"dig.grass", // eSoundType_DIG_GRASS + L"dig.gravel", // eSoundType_DIG_GRAVEL + L"dig.sand", // eSoundType_DIG_SAND + L"dig.snow", // eSoundType_DIG_SNOW + L"dig.stone", // eSoundType_DIG_STONE + L"dig.wood", // eSoundType_DIG_WOOD +}; + + +const WCHAR *ConsoleSoundEngine::wchUISoundNames[eSFX_MAX]= +{ + L"back", + L"craft", + L"craftfail", + L"focus", + L"press", + L"scroll", +}; diff --git a/Minecraft.Client/Common/BuildVer.h b/Minecraft.Client/Common/BuildVer.h new file mode 100644 index 0000000..ee558b0 --- /dev/null +++ b/Minecraft.Client/Common/BuildVer.h @@ -0,0 +1,57 @@ + +#pragma once + + +#define VER_PRODUCTMAJORVERSION 0 +#define VER_PRODUCTMINORVERSION 0 + +// This goes up with each build +// 4J-JEV: This value is extracted with a regex so it can be placed as the version in the AppX manifest on Durango. +#define VER_PRODUCTBUILD 495 +// This goes up if there is any change to network traffic or code in a build +#define VER_NETWORK 495 +#define VER_PRODUCTBUILD_QFE 0 + +#define VER_FILEVERSION_STRING "1.3" +#define VER_PRODUCTVERSION_STRING VER_FILEVERSION_STRING +#define VER_FILEVERSION_STRING_W L"1.3" +#define VER_PRODUCTVERSION_STRING_W VER_FILEVERSION_STRING_W +#define VER_FILEBETA_STR "" +#undef VER_FILEVERSION +#define VER_FILEVERSION VER_PRODUCTMAJORVERSION, VER_PRODUCTMINORVERSION, VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE +#define VER_PRODUCTVERSION VER_PRODUCTMAJORVERSION, VER_PRODUCTMINORVERSION, VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE + +#if (VER_PRODUCTBUILD < 10) +#define VER_FILEBPAD "000" +#define VER_FILEBPAD_W L"000" +#elif (VER_PRODUCTBUILD < 100) +#define VER_FILEBPAD "00" +#define VER_FILEBPAD_W L"00" +#elif (VER_PRODUCTBUILD < 1000) +#define VER_FILEBPAD "0" +#define VER_FILEBPAD_W L"0" +#else +#define VER_FILEBPAD +#define VER_FILEBPAD_W +#endif + +#define VER_WIDE_PREFIX(x) L##x + +#define VER_FILEVERSION_STR2(x,y) VER_FILEVERSION_STRING "." VER_FILEBPAD #x "." #y +#define VER_FILEVERSION_STR2_W(x,y) VER_FILEVERSION_STRING_W L"." VER_FILEBPAD_W VER_WIDE_PREFIX(#x) L"." VER_WIDE_PREFIX(#y) +#define VER_FILEVERSION_STR1(x,y) VER_FILEVERSION_STR2(x, y) +#define VER_FILEVERSION_STR1_W(x,y) VER_FILEVERSION_STR2_W(x, y) + +#undef VER_FILEVERSION_STR +#define VER_FILEVERSION_STR VER_FILEVERSION_STR1(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE) +#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR1(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE) + +#define VER_FILEVERSION_STR_W VER_FILEVERSION_STR1_W(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE) +#define VER_PRODUCTVERSION_STR_W VER_FILEVERSION_STR1_W(VER_PRODUCTBUILD, VER_PRODUCTBUILD_QFE) + +#if (VER_PRODUCTBUILD_QFE >= 256) +#error "QFE number cannot exceed 255" +#endif + + + diff --git a/Minecraft.Client/Common/C4JMemoryPool.h b/Minecraft.Client/Common/C4JMemoryPool.h new file mode 100644 index 0000000..e1e795e --- /dev/null +++ b/Minecraft.Client/Common/C4JMemoryPool.h @@ -0,0 +1,176 @@ + +#pragma once + + +#include + +class C4JMemoryPool +{ +public: + unsigned int Align(unsigned int val, unsigned int align) { return int((val+(align-1))/align) * align; } + virtual void* Alloc(size_t size) = 0; + virtual void Free(void* ptr) = 0; +}; + + + +// Fast Efficient Fixed-Size Memory Pool : No Loops and No Overhead +// http://www.alogicalmind.com/memory_pools/index.htm +class C4JMemoryPoolFixed : public C4JMemoryPool +{ + // Basic type define + typedef unsigned int uint; + typedef unsigned char uchar; + uint m_numOfBlocks; // Num of blocks + uint m_sizeOfEachBlock; // Size of each block + uint m_numFreeBlocks; // Num of remaining blocks + uint m_numInitialized; // Num of initialized blocks + uchar* m_memStart; // Beginning of memory pool + uchar* m_memEnd; // End of memory pool + uchar* m_next; // Num of next free block +// CRITICAL_SECTION m_CS; +public: + C4JMemoryPoolFixed() + { + m_numOfBlocks = 0; + m_sizeOfEachBlock = 0; + m_numFreeBlocks = 0; + m_numInitialized = 0; + m_memStart = NULL; + m_memEnd = NULL; + m_next = 0; + } + + C4JMemoryPoolFixed(uint sizeOfEachBlock, uint numOfBlocks) + { + CreatePool(sizeOfEachBlock, numOfBlocks); + } + + ~C4JMemoryPoolFixed() { DestroyPool(); } + + void CreatePool(uint sizeOfEachBlock, uint numOfBlocks) + { + assert(sizeOfEachBlock >= 4); // has to be at least the size of an int, for book keeping + m_numOfBlocks = numOfBlocks; + m_sizeOfEachBlock = sizeOfEachBlock; + m_numFreeBlocks = numOfBlocks; + m_numInitialized = 0; + m_memStart = new uchar[ m_sizeOfEachBlock * + m_numOfBlocks ]; + m_memEnd = m_memStart + (m_sizeOfEachBlock * m_numOfBlocks); + m_next = m_memStart; +// InitializeCriticalSection(&m_CS); + } + + void DestroyPool() + { + delete[] m_memStart; + m_memStart = NULL; + } + + uchar* AddrFromIndex(uint i) const + { + return m_memStart + ( i * m_sizeOfEachBlock ); + } + + uint IndexFromAddr(const uchar* p) const + { + return (((uint)(p - m_memStart)) / m_sizeOfEachBlock); + } + + virtual void* Alloc(size_t size) + { + if(size > m_sizeOfEachBlock) + return ::malloc(size); +// EnterCriticalSection(&m_CS); + if (m_numInitialized < m_numOfBlocks ) + { + uint* p = (uint*)AddrFromIndex( m_numInitialized ); + *p = m_numInitialized + 1; + m_numInitialized++; + } + void* ret = NULL; + if ( m_numFreeBlocks > 0 ) + { + ret = (void*)m_next; + --m_numFreeBlocks; + if (m_numFreeBlocks!=0) + { + m_next = AddrFromIndex( *((uint*)m_next) ); + } + else + { + m_next = NULL; + } + } +// LeaveCriticalSection(&m_CS); + return ret; + } + + virtual void Free(void* ptr) + { + if(ptr < m_memStart || ptr > m_memEnd) + { + ::free(ptr); + return; + } +// EnterCriticalSection(&m_CS); + if (m_next != NULL) + { + (*(uint*)ptr) = IndexFromAddr( m_next ); + m_next = (uchar*)ptr; + } + else + { + *((uint*)ptr) = m_numOfBlocks; + m_next = (uchar*)ptr; + } + ++m_numFreeBlocks; +// LeaveCriticalSection(&m_CS); + } +}; // End pool class + + +// this pool will constantly grow until it is reset (automatically when all allocs have been "freed") +class C4JMemoryPoolGrow : public C4JMemoryPool +{ + uint32_t m_totalSize; + uint32_t m_memUsed; + uint32_t m_numAllocations; + uint8_t* m_pMemory; + uint32_t m_currentOffset; + +public: + C4JMemoryPoolGrow(uint32_t size = 64*1024) + { + size = Align(size, 4); + m_totalSize = size; + m_pMemory = new uint8_t[size]; + m_currentOffset = 0; + m_memUsed = 0; + m_numAllocations = 0; + } + + virtual void* Alloc(size_t size) + { + size = Align(size, 4); // 4 byte align the memory + assert((m_currentOffset + size) < m_totalSize); // make sure we haven't ran out of space + void* returnMem = &m_pMemory[m_currentOffset]; // grab the return memory + m_currentOffset += size; + m_numAllocations++; + return returnMem; + } + virtual void Free(void* ptr) + { + m_numAllocations--; + if(m_numAllocations == 0) + m_currentOffset = 0; // reset the pool when we reach zero allocations + } +}; + + + + + + + diff --git a/Minecraft.Client/Common/C4JMemoryPoolAllocator.h b/Minecraft.Client/Common/C4JMemoryPoolAllocator.h new file mode 100644 index 0000000..a46cc76 --- /dev/null +++ b/Minecraft.Client/Common/C4JMemoryPoolAllocator.h @@ -0,0 +1,113 @@ + + +#pragma once +#include "..\Minecraft.Client\Common\C4JMemoryPool.h" + +// Custom allocator, takes a C4JMemoryPool class, which can be one of a number of pool implementations. + +template +class C4JPoolAllocator +{ +public: + typedef T value_type; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + typedef T* pointer; + typedef const T* const_pointer; + + typedef T& reference; + typedef const T& const_reference; + + //! A struct to construct an allocator for a different type. + template + struct rebind { typedef C4JPoolAllocator other; }; + + + C4JMemoryPool* m_pPool; + bool m_selfAllocated; + + C4JPoolAllocator( C4JMemoryPool* pool = new C4JMemoryPoolFixed(32, 4096 )) : m_pPool( pool ), m_selfAllocated(true) + { + printf("allocated mempool\n"); + } + + template + C4JPoolAllocator(C4JPoolAllocator const& obj) : m_pPool( obj.m_pPool ), m_selfAllocated(false) // copy constructor + { + printf("C4JPoolAllocator constructed from 0x%08x\n", &obj); + assert(obj.m_pPool); + } +private: + +public: + + ~C4JPoolAllocator() + { + if(m_selfAllocated) + delete m_pPool; + } + + pointer address( reference r ) const { return &r; } + const_pointer address( const_reference r ) const { return &r; } + + pointer allocate( size_type n, const void* /*hint*/=0 ) + { + assert(m_pPool); + return (pointer)m_pPool->Alloc(n * sizeof(T)); + } + + void deallocate( pointer p, size_type /*n*/ ) + { + assert(m_pPool); + m_pPool->Free(p); + } + + void construct( pointer p, const T& val ) + { + new (p) T(val); + } + + void destroy( pointer p ) + { + p->~T(); + } + + size_type max_size() const + { + return ULONG_MAX / sizeof(T); + } + +}; + + +template +bool +operator==( const C4JPoolAllocator& left, const C4JPoolAllocator& right ) +{ + if (left.m_pPool == right.m_pPool) + { + return true; + } + return false; +} + +template +bool +operator!=( const C4JPoolAllocator& left, const C4JPoolAllocator& right) +{ + if (left.m_pPool != right.m_pPool) + { + return true; + } + return false; +} + + + + + + + + + diff --git a/Minecraft.Client/Common/Colours/ColourTable.cpp b/Minecraft.Client/Common/Colours/ColourTable.cpp new file mode 100644 index 0000000..dc58cfb --- /dev/null +++ b/Minecraft.Client/Common/Colours/ColourTable.cpp @@ -0,0 +1,366 @@ +#include "stdafx.h" +#include "ColourTable.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" + +unordered_map ColourTable::s_colourNamesMap; + +wchar_t *ColourTable::ColourTableElements[eMinecraftColour_COUNT] = +{ + L"NOTSET", + + L"Foliage_Evergreen", + L"Foliage_Birch", + L"Foliage_Default", + L"Foliage_Common", + L"Foliage_Ocean", + L"Foliage_Plains", + L"Foliage_Desert", + L"Foliage_ExtremeHills", + L"Foliage_Forest", + L"Foliage_Taiga", + L"Foliage_Swampland", + L"Foliage_River", + L"Foliage_Hell", + L"Foliage_Sky", + L"Foliage_FrozenOcean", + L"Foliage_FrozenRiver", + L"Foliage_IcePlains", + L"Foliage_IceMountains", + L"Foliage_MushroomIsland", + L"Foliage_MushroomIslandShore", + L"Foliage_Beach", + L"Foliage_DesertHills", + L"Foliage_ForestHills", + L"Foliage_TaigaHills", + L"Foliage_ExtremeHillsEdge", + L"Foliage_Jungle", + L"Foliage_JungleHills", + + L"Grass_Common", + L"Grass_Ocean", + L"Grass_Plains", + L"Grass_Desert", + L"Grass_ExtremeHills", + L"Grass_Forest", + L"Grass_Taiga", + L"Grass_Swampland", + L"Grass_River", + L"Grass_Hell", + L"Grass_Sky", + L"Grass_FrozenOcean", + L"Grass_FrozenRiver", + L"Grass_IcePlains", + L"Grass_IceMountains", + L"Grass_MushroomIsland", + L"Grass_MushroomIslandShore", + L"Grass_Beach", + L"Grass_DesertHills", + L"Grass_ForestHills", + L"Grass_TaigaHills", + L"Grass_ExtremeHillsEdge", + L"Grass_Jungle", + L"Grass_JungleHills", + + L"Water_Ocean", + L"Water_Plains", + L"Water_Desert", + L"Water_ExtremeHills", + L"Water_Forest", + L"Water_Taiga", + L"Water_Swampland", + L"Water_River", + L"Water_Hell", + L"Water_Sky", + L"Water_FrozenOcean", + L"Water_FrozenRiver", + L"Water_IcePlains", + L"Water_IceMountains", + L"Water_MushroomIsland", + L"Water_MushroomIslandShore", + L"Water_Beach", + L"Water_DesertHills", + L"Water_ForestHills", + L"Water_TaigaHills", + L"Water_ExtremeHillsEdge", + L"Water_Jungle", + L"Water_JungleHills", + + L"Sky_Ocean", + L"Sky_Plains", + L"Sky_Desert", + L"Sky_ExtremeHills", + L"Sky_Forest", + L"Sky_Taiga", + L"Sky_Swampland", + L"Sky_River", + L"Sky_Hell", + L"Sky_Sky", + L"Sky_FrozenOcean", + L"Sky_FrozenRiver", + L"Sky_IcePlains", + L"Sky_IceMountains", + L"Sky_MushroomIsland", + L"Sky_MushroomIslandShore", + L"Sky_Beach", + L"Sky_DesertHills", + L"Sky_ForestHills", + L"Sky_TaigaHills", + L"Sky_ExtremeHillsEdge", + L"Sky_Jungle", + L"Sky_JungleHills", + + L"Tile_RedstoneDust", + L"Tile_RedstoneDustUnlit", + L"Tile_RedstoneDustLitMin", + L"Tile_RedstoneDustLitMax", + L"Tile_StemMin", + L"Tile_StemMax", + L"Tile_WaterLily", + + L"Sky_Dawn_Dark", + L"Sky_Dawn_Bright", + + L"Material_None", + L"Material_Grass", + L"Material_Sand", + L"Material_Cloth", + L"Material_Fire", + L"Material_Ice", + L"Material_Metal", + L"Material_Plant", + L"Material_Snow", + L"Material_Clay", + L"Material_Dirt", + L"Material_Stone", + L"Material_Water", + L"Material_Wood", + L"Material_Emerald", + + L"Particle_Note_00", + L"Particle_Note_01", + L"Particle_Note_02", + L"Particle_Note_03", + L"Particle_Note_04", + L"Particle_Note_05", + L"Particle_Note_06", + L"Particle_Note_07", + L"Particle_Note_08", + L"Particle_Note_09", + L"Particle_Note_10", + L"Particle_Note_11", + L"Particle_Note_12", + L"Particle_Note_13", + L"Particle_Note_14", + L"Particle_Note_15", + L"Particle_Note_16", + L"Particle_Note_17", + L"Particle_Note_18", + L"Particle_Note_19", + L"Particle_Note_20", + L"Particle_Note_21", + L"Particle_Note_22", + L"Particle_Note_23", + L"Particle_Note_24", + + L"Particle_NetherPortal", + L"Particle_EnderPortal", + L"Particle_Smoke", + L"Particle_Ender", + + L"Particle_Explode", + L"Particle_HugeExplosion", + + L"Particle_DripWater", + L"Particle_DripLavaStart", + L"Particle_DripLavaEnd", + + L"Particle_EnchantmentTable", + L"Particle_DragonBreathMin", + L"Particle_DragonBreathMax", + L"Particle_Suspend", + + L"Particle_CritStart", // arrow in air + L"Particle_CritEnd", // arrow in air + + L"Effect_MovementSpeed", + L"Effect_MovementSlowDown", + L"Effect_DigSpeed", + L"Effect_DigSlowdown", + L"Effect_DamageBoost", + L"Effect_Heal", + L"Effect_Harm", + L"Effect_Jump", + L"Effect_Confusion", + L"Effect_Regeneration", + L"Effect_DamageResistance", + L"Effect_FireResistance", + L"Effect_WaterBreathing", + L"Effect_Invisiblity", + L"Effect_Blindness", + L"Effect_NightVision", + L"Effect_Hunger", + L"Effect_Weakness", + L"Effect_Poison", + + L"Potion_BaseColour", + + L"Mob_Creeper_Colour1", + L"Mob_Creeper_Colour2", + L"Mob_Skeleton_Colour1", + L"Mob_Skeleton_Colour2", + L"Mob_Spider_Colour1", + L"Mob_Spider_Colour2", + L"Mob_Zombie_Colour1", + L"Mob_Zombie_Colour2", + L"Mob_Slime_Colour1", + L"Mob_Slime_Colour2", + L"Mob_Ghast_Colour1", + L"Mob_Ghast_Colour2", + L"Mob_PigZombie_Colour1", + L"Mob_PigZombie_Colour2", + L"Mob_Enderman_Colour1", + L"Mob_Enderman_Colour2", + L"Mob_CaveSpider_Colour1", + L"Mob_CaveSpider_Colour2", + L"Mob_Silverfish_Colour1", + L"Mob_Silverfish_Colour2", + L"Mob_Blaze_Colour1", + L"Mob_Blaze_Colour2", + L"Mob_LavaSlime_Colour1", + L"Mob_LavaSlime_Colour2", + L"Mob_Pig_Colour1", + L"Mob_Pig_Colour2", + L"Mob_Sheep_Colour1", + L"Mob_Sheep_Colour2", + L"Mob_Cow_Colour1", + L"Mob_Cow_Colour2", + L"Mob_Chicken_Colour1", + L"Mob_Chicken_Colour2", + L"Mob_Squid_Colour1", + L"Mob_Squid_Colour2", + L"Mob_Wolf_Colour1", + L"Mob_Wolf_Colour2", + L"Mob_MushroomCow_Colour1", + L"Mob_MushroomCow_Colour2", + L"Mob_Ocelot_Colour1", + L"Mob_Ocelot_Colour2", + L"Mob_Villager_Colour1", + L"Mob_Villager_Colour2", + + L"Armour_Default_Leather_Colour", + L"Under_Water_Clear_Colour", + L"Under_Lava_Clear_Colour", + L"In_Cloud_Base_Colour", + + L"Under_Water_Fog_Colour", + L"Under_Lava_Fog_Colour", + L"In_Cloud_Fog_Colour", + + L"Default_Fog_Colour", + L"Nether_Fog_Colour", + L"End_Fog_Colour", + + L"Sign_Text", + L"Map_Text", + + L"HTMLColor_0", + L"HTMLColor_1", + L"HTMLColor_2", + L"HTMLColor_3", + L"HTMLColor_4", + L"HTMLColor_5", + L"HTMLColor_6", + L"HTMLColor_7", + L"HTMLColor_8", + L"HTMLColor_9", + L"HTMLColor_a", + L"HTMLColor_b", + L"HTMLColor_c", + L"HTMLColor_d", + L"HTMLColor_e", + L"HTMLColor_f", + L"HTMLColor_dark_0", + L"HTMLColor_dark_1", + L"HTMLColor_dark_2", + L"HTMLColor_dark_3", + L"HTMLColor_dark_4", + L"HTMLColor_dark_5", + L"HTMLColor_dark_6", + L"HTMLColor_dark_7", + L"HTMLColor_dark_8", + L"HTMLColor_dark_9", + L"HTMLColor_dark_a", + L"HTMLColor_dark_b", + L"HTMLColor_dark_c", + L"HTMLColor_dark_d", + L"HTMLColor_dark_e", + L"HTMLColor_dark_f", + L"HTMLColor_T1", + L"HTMLColor_T2", + L"HTMLColor_T3", + L"HTMLColor_Black", + L"HTMLColor_White", + L"Color_EnchantText", + L"Color_EnchantTextFocus", + L"Color_EnchantTextDisabled", + L"Color_RenamedItemTitle", +}; + +void ColourTable::staticCtor() +{ + for(unsigned int i = eMinecraftColour_NOT_SET; i < eMinecraftColour_COUNT; ++i) + { + s_colourNamesMap.insert( unordered_map::value_type( ColourTableElements[i], (eMinecraftColour)i) ); + } +} + +ColourTable::ColourTable(PBYTE pbData, DWORD dwLength) +{ + loadColoursFromData(pbData, dwLength); +} + +ColourTable::ColourTable(ColourTable *defaultColours, PBYTE pbData, DWORD dwLength) +{ + // 4J Stu - Default the colours that of the table passed in + XMemCpy( (void *)m_colourValues, (void *)defaultColours->m_colourValues, sizeof(int) * eMinecraftColour_COUNT); + loadColoursFromData(pbData, dwLength); +} +void ColourTable::loadColoursFromData(PBYTE pbData, DWORD dwLength) +{ + byteArray src(pbData, dwLength); + + ByteArrayInputStream bais(src); + DataInputStream dis(&bais); + + int versionNumber = dis.readInt(); + int coloursCount = dis.readInt(); + + for(int i = 0; i < coloursCount; ++i) + { + wstring colourId = dis.readUTF(); + int colourValue = dis.readInt(); + setColour(colourId, colourValue); + AUTO_VAR(it,s_colourNamesMap.find(colourId)); + } + + bais.reset(); +} + +void ColourTable::setColour(const wstring &colourName, int value) +{ + AUTO_VAR(it,s_colourNamesMap.find(colourName)); + if(it != s_colourNamesMap.end()) + { + m_colourValues[(int)it->second] = value; + } +} + +void ColourTable::setColour(const wstring &colourName, const wstring &value) +{ + setColour(colourName, _fromHEXString(value)); +} + +unsigned int ColourTable::getColour(eMinecraftColour id) +{ + return m_colourValues[(int)id]; +} diff --git a/Minecraft.Client/Common/Colours/ColourTable.h b/Minecraft.Client/Common/Colours/ColourTable.h new file mode 100644 index 0000000..8e0a348 --- /dev/null +++ b/Minecraft.Client/Common/Colours/ColourTable.h @@ -0,0 +1,23 @@ +#pragma once + +class ColourTable +{ +private: + unsigned int m_colourValues[eMinecraftColour_COUNT]; + + static wchar_t *ColourTableElements[eMinecraftColour_COUNT]; + static unordered_map s_colourNamesMap; + +public: + static void staticCtor(); + + ColourTable(PBYTE pbData, DWORD dwLength); + ColourTable(ColourTable *defaultColours, PBYTE pbData, DWORD dwLength); + + unsigned int getColour(eMinecraftColour id); + unsigned int getColor(eMinecraftColour id) { return getColour(id); } + + void loadColoursFromData(PBYTE pbData, DWORD dwLength); + void setColour(const wstring &colourName, int value); + void setColour(const wstring &colourName, const wstring &value); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/CommonMedia.sln b/Minecraft.Client/Common/CommonMedia.sln new file mode 100644 index 0000000..9f83988 --- /dev/null +++ b/Minecraft.Client/Common/CommonMedia.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CommonMedia", "CommonMedia.vcxproj", "{21BBD32C-AF5E-4741-8B80-3B73FC0D0F27}" +EndProject +Global + GlobalSection(TeamFoundationVersionControl) = preSolution + SccNumberOfProjects = 2 + SccEnterpriseProvider = {4CA58AB2-18FA-4F8D-95D4-32DDF27D184C} + SccTeamFoundationServer = http://tfs_server:8080/tfs/storiespark + SccProjectUniqueName0 = CommonMedia.vcxproj + SccLocalPath0 = . + SccLocalPath1 = . + EndGlobalSection + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {21BBD32C-AF5E-4741-8B80-3B73FC0D0F27}.Debug|Win32.ActiveCfg = Debug|Win32 + {21BBD32C-AF5E-4741-8B80-3B73FC0D0F27}.Debug|Win32.Build.0 = Debug|Win32 + {21BBD32C-AF5E-4741-8B80-3B73FC0D0F27}.Release|Win32.ActiveCfg = Release|Win32 + {21BBD32C-AF5E-4741-8B80-3B73FC0D0F27}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Minecraft.Client/Common/CommonMedia.vcxproj b/Minecraft.Client/Common/CommonMedia.vcxproj new file mode 100644 index 0000000..5a472e0 --- /dev/null +++ b/Minecraft.Client/Common/CommonMedia.vcxproj @@ -0,0 +1,115 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {21BBD32C-AF5E-4741-8B80-3B73FC0D0F27} + MakeFileProj + SAK + SAK + SAK + SAK + + + + Makefile + true + v110 + + + Makefile + false + v110 + + + + + + + + + + + + + WIN32;_DEBUG;$(NMakePreprocessorDefinitions) + echo Creating languages.loc +copy .\Media\strings.resx .\Media\en-EN.lang +copy .\Media\fr-FR\strings.resx .\Media\fr-FR\fr-FR.lang +copy .\Media\ja-JP\strings.resx .\Media\ja-JP\ja-JP.lang +..\..\..\Tools\NewLocalisationPacker.exe --static .\Media .\Media\languages.loc + +echo Making archive +..\..\..\Tools\ArchiveFilePacker.exe -cd $(ProjectDir)\Media media.arc media.txt + +echo Copying Durango strings.h +copy .\Media\strings.h ..\Durango\strings.h + +echo Copying PS3 strings.h +copy .\Media\strings.h ..\PS3\strings.h + +echo Copying PS4 strings.h +copy .\Media\strings.h ..\Orbis\strings.h + +echo Copying Win strings.h +copy .\Media\strings.h ..\Windows64\strings.h + + + WIN32;NDEBUG;$(NMakePreprocessorDefinitions) + + + + + + + \ No newline at end of file diff --git a/Minecraft.Client/Common/CommonMedia.vcxproj.filters b/Minecraft.Client/Common/CommonMedia.vcxproj.filters new file mode 100644 index 0000000..9fb0927 --- /dev/null +++ b/Minecraft.Client/Common/CommonMedia.vcxproj.filters @@ -0,0 +1,136 @@ + + + + + {55c7ab2e-b3e5-4aed-9ffe-3308591d9c34} + + + {eaa0eb72-0b27-4080-ad53-f68e42f37ba8} + + + {711ad95b-eb56-4e18-b001-34ad7b8075a3} + + + {1432ec3d-c5d0-46da-91b6-e7737095a97e} + + + {4b2aeaf1-04d7-454d-b2d9-08364799831c} + + + {4b0eaef6-fa2f-4605-b0da-a81ffb5659bc} + + + {bf1c74da-21f1-4bdd-98ed-83457946e4cc} + + + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + Archive + + + Archive + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + IggyMedia + + + + + Strings + + + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Strings + + + Archive + + + + + Archive\Durango + + + Archive\PS3 + + + Archive\PS4 + + + Archive\Win64 + + + \ No newline at end of file diff --git a/Minecraft.Client/Common/ConsoleGameMode.cpp b/Minecraft.Client/Common/ConsoleGameMode.cpp new file mode 100644 index 0000000..b080e62 --- /dev/null +++ b/Minecraft.Client/Common/ConsoleGameMode.cpp @@ -0,0 +1,9 @@ +#include "stdafx.h" +#include "ConsoleGameMode.h" +#include "..\Common\Tutorial\Tutorial.h" + +ConsoleGameMode::ConsoleGameMode(int iPad, Minecraft *minecraft, ClientConnection *connection) + : TutorialMode(iPad, minecraft, connection) +{ + tutorial = new Tutorial(iPad); +} \ No newline at end of file diff --git a/Minecraft.Client/Common/ConsoleGameMode.h b/Minecraft.Client/Common/ConsoleGameMode.h new file mode 100644 index 0000000..3e486cb --- /dev/null +++ b/Minecraft.Client/Common/ConsoleGameMode.h @@ -0,0 +1,10 @@ +#pragma once +#include "..\Common\Tutorial\TutorialMode.h" + +class ConsoleGameMode : public TutorialMode +{ +public: + ConsoleGameMode(int iPad, Minecraft *minecraft, ClientConnection *connection); + + virtual bool isImplemented() { return true; } +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/Console_Awards_enum.h b/Minecraft.Client/Common/Console_Awards_enum.h new file mode 100644 index 0000000..9597c71 --- /dev/null +++ b/Minecraft.Client/Common/Console_Awards_enum.h @@ -0,0 +1,72 @@ +#pragma once + +enum eAward +{ + eAward_TakingInventory=0, + eAward_GettingWood, + eAward_Benchmarking, + eAward_TimeToMine, + eAward_HotTopic, + eAward_AquireHardware, + eAward_TimeToFarm, + eAward_BakeBread, + eAward_TheLie, + eAward_GettingAnUpgrade, + eAward_DeliciousFish, + eAward_OnARail, + eAward_TimeToStrike, + eAward_MonsterHunter, + eAward_CowTipper, + eAward_WhenPigsFly, + eAward_LeaderOfThePack, + eAward_MOARTools, + eAward_DispenseWithThis, + eAward_InToTheNether, + + eAward_mine100Blocks, + eAward_kill10Creepers, + eAward_eatPorkChop, + eAward_play100Days, + eAward_arrowKillCreeper, + eAward_socialPost, + +#ifndef _XBOX + // 4J Stu - Does not map to any Xbox achievements + eAward_snipeSkeleton, + eAward_diamonds, + eAward_portal, + eAward_ghast, + eAward_blazeRod, + eAward_potion, + eAward_theEnd, + eAward_winGame, + eAward_enchantments, + eAward_overkill, + eAward_bookcase, +#endif + +#ifdef _EXTENDED_ACHIEVEMENTS + eAward_adventuringTime, + eAward_repopulation, + //eAward_porkChop, + eAward_diamondsToYou, + //eAward_passingTheTime, + //eAward_archer, + eAward_theHaggler, + eAward_potPlanter, + eAward_itsASign, + eAward_ironBelly, + eAward_haveAShearfulDay, + eAward_rainbowCollection, + eAward_stayinFrosty, + eAward_chestfulOfCobblestone, + eAward_renewableEnergy, + eAward_musicToMyEars, + eAward_bodyGuard, + eAward_ironMan, + eAward_zombieDoctor, + eAward_lionTamer, +#endif + + eAward_Max, +}; diff --git a/Minecraft.Client/Common/Console_Debug_enum.h b/Minecraft.Client/Common/Console_Debug_enum.h new file mode 100644 index 0000000..4e6c2b1 --- /dev/null +++ b/Minecraft.Client/Common/Console_Debug_enum.h @@ -0,0 +1,42 @@ +#pragma once + +enum eDebugSetting +{ + eDebugSetting_LoadSavesFromDisk, + eDebugSetting_WriteSavesToDisk, + eDebugSetting_FreezePlayers, //eDebugSetting_InterfaceOff, + eDebugSetting_Safearea, + eDebugSetting_MobsDontAttack, + eDebugSetting_FreezeTime, + eDebugSetting_DisableWeather, + eDebugSetting_CraftAnything, + eDebugSetting_UseDpadForDebug, + eDebugSetting_MobsDontTick, + eDebugSetting_InstantDestroy, + eDebugSetting_ShowUIConsole, + eDebugSetting_DistributableSave, + eDebugSetting_DebugLeaderboards, + eDebugSetting_EnableHeightWaterBiomeOverride, //eDebugSetting_TipsAlwaysOn, + eDebugSetting_SuperflatNether, + //eDebugSetting_LightDarkBackground, + eDebugSetting_RegularLightning, + eDebugSetting_GoToNether, + //eDebugSetting_GoToEnd, + eDebugSetting_GoToOverworld, + eDebugSetting_UnlockAllDLC, // eDebugSetting_ToggleFont, + eDebugSetting_ShowUIMarketingGuide, + eDebugSetting_Max, +}; + +enum eDebugButton +{ + eDebugButton_Theme=0, + eDebugButton_Avatar_Item_1, + eDebugButton_Avatar_Item_2, + eDebugButton_Avatar_Item_3, + eDebugButton_Gamerpic_1, + eDebugButton_Gamerpic_2, + eDebugButton_CheckTips, + eDebugButton_WipeLeaderboards, + eDebugButton_Max, +}; diff --git a/Minecraft.Client/Common/Console_Utils.cpp b/Minecraft.Client/Common/Console_Utils.cpp new file mode 100644 index 0000000..cb0f1b5 --- /dev/null +++ b/Minecraft.Client/Common/Console_Utils.cpp @@ -0,0 +1,40 @@ +#include "stdafx.h" + +//-------------------------------------------------------------------------------------- +// Name: DebugSpewV() +// Desc: Internal helper function +//-------------------------------------------------------------------------------------- +#ifndef _CONTENT_PACKAGE +static VOID DebugSpewV( const CHAR* strFormat, const va_list pArgList ) +{ +#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ + assert(0); +#else + CHAR str[2048]; + // Use the secure CRT to avoid buffer overruns. Specify a count of + // _TRUNCATE so that too long strings will be silently truncated + // rather than triggering an error. + _vsnprintf_s( str, _TRUNCATE, strFormat, pArgList ); + OutputDebugStringA( str ); +#endif +} +#endif + +//-------------------------------------------------------------------------------------- +// Name: DebugSpew() +// Desc: Prints formatted debug spew +//-------------------------------------------------------------------------------------- +#ifdef _Printf_format_string_ // VC++ 2008 and later support this annotation +VOID CDECL DebugSpew( _In_z_ _Printf_format_string_ const CHAR* strFormat, ... ) +#else +VOID CDECL DebugPrintf( const CHAR* strFormat, ... ) +#endif +{ +#ifndef _CONTENT_PACKAGE + va_list pArgList; + va_start( pArgList, strFormat ); + DebugSpewV( strFormat, pArgList ); + va_end( pArgList ); +#endif +} + diff --git a/Minecraft.Client/Common/Consoles_App.cpp b/Minecraft.Client/Common/Consoles_App.cpp new file mode 100644 index 0000000..cf855ca --- /dev/null +++ b/Minecraft.Client/Common/Consoles_App.cpp @@ -0,0 +1,9539 @@ + +#include "stdafx.h" + +#include "..\..\Minecraft.World\Recipy.h" +#include "..\..\Minecraft.Client\Options.h" +#include "..\..\Minecraft.World\AABB.h" +#include "..\..\Minecraft.World\Vec3.h" +#include "..\MinecraftServer.h" +#include "..\MultiPlayerLevel.h" +#include "..\GameRenderer.h" +#include "..\ProgressRenderer.h" +#include "..\..\Minecraft.Client\LevelRenderer.h" +#include "..\..\Minecraft.Client\MobSkinMemTextureProcessor.h" +#include "..\..\Minecraft.Client\Minecraft.h" +#include "..\ClientConnection.h" +#include "..\MultiPlayerLocalPlayer.h" +#include "..\..\Minecraft.Client\LocalPlayer.h" +#include "..\..\Minecraft.World\Player.h" +#include "..\..\Minecraft.World\Inventory.h" +#include "..\..\Minecraft.World\Level.h" +#include "..\..\Minecraft.World\FurnaceTileEntity.h" +#include "..\..\Minecraft.World\Container.h" +#include "..\..\Minecraft.World\DispenserTileEntity.h" +#include "..\..\Minecraft.World\SignTileEntity.h" +#include "..\..\Minecraft.Client\StatsCounter.h" +#include "..\GameMode.h" +#include "..\Xbox\Social\SocialManager.h" +#include "Tutorial\TutorialMode.h" +#if defined _XBOX || defined _WINDOWS64 +#include "..\..\Minecraft.Client\Xbox\XML\ATGXmlParser.h" +#include "..\..\Minecraft.Client\Xbox\XML\xmlFilesCallback.h" +#endif +#include "Minecraft_Macros.h" +#include "..\..\Minecraft.Client\PlayerList.h" +#include "..\..\Minecraft.Client\ServerPlayer.h" +#include "GameRules\ConsoleGameRules.h" +#include "GameRules\ConsoleSchematicFile.h" +#include "..\..\Minecraft.World\InputOutputStream.h" +#include "..\..\Minecraft.World\LevelSettings.h" +#include "..\User.h" +#include "..\..\Minecraft.World\LevelData.h" +#include "..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "..\..\Minecraft.Client\EntityRenderDispatcher.h" +#include "..\..\Minecraft.World\compression.h" +#include "..\TexturePackRepository.h" +#include "..\DLCTexturePack.h" +#include "DLC\DLCPack.h" +#include "..\StringTable.h" +#ifndef _XBOX +#include "..\ArchiveFile.h" +#endif +#include "..\Minecraft.h" +#ifdef _XBOX +#include "..\Xbox\GameConfig\Minecraft.spa.h" +#include "..\Xbox\Network\NetworkPlayerXbox.h" +#include "XUI\XUI_TextEntry.h" +#include "XUI\XUI_XZP_Icons.h" +#include "XUI\XUI_PauseMenu.h" +#else +#include "UI\UI.h" +#include "UI\UIScene_PauseMenu.h" +#endif +#ifdef __PS3__ +#include +#endif +#ifdef __ORBIS__ +#include +#endif + +#include "..\Common\Leaderboards\LeaderboardManager.h" + +//CMinecraftApp app; +unsigned int CMinecraftApp::m_uiLastSignInData = 0; + +const float CMinecraftApp::fSafeZoneX = 64.0f; // 5% of 1280 +const float CMinecraftApp::fSafeZoneY = 36.0f; // 5% of 720 + +int CMinecraftApp::s_iHTMLFontSizesA[eHTMLSize_COUNT] = +{ +#ifdef _XBOX + 14,12,14,24 +#else + //20,15,20,24 + 20,13,20,26 +#endif +}; + + +CMinecraftApp::CMinecraftApp() +{ + if(GAME_SETTINGS_PROFILE_DATA_BYTES != sizeof(GAME_SETTINGS)) + { + // 4J Stu - See comment for GAME_SETTINGS_PROFILE_DATA_BYTES in Xbox_App.h + DebugPrintf("WARNING: The size of the profile GAME_SETTINGS struct has changed, so all stat data is likely incorrect. Is: %d, Should be: %d\n",sizeof(GAME_SETTINGS),GAME_SETTINGS_PROFILE_DATA_BYTES); +#ifndef _CONTENT_PACKAGE + __debugbreak(); +#endif + } + + for(int i=0;i; + } + + LocaleAndLanguageInit(); + +#ifdef _XBOX_ONE + m_hasReachedMainMenu = false; +#endif +} + + + +void CMinecraftApp::DebugPrintf(const char *szFormat, ...) +{ + +#ifndef _FINAL_BUILD + char buf[1024]; + va_list ap; + va_start(ap, szFormat); + vsnprintf(buf, sizeof(buf), szFormat, ap); + va_end(ap); + OutputDebugStringA(buf); +#endif + +} + +void CMinecraftApp::DebugPrintf(int user, const char *szFormat, ...) +{ +#ifndef _FINAL_BUILD + if(user == USER_NONE) + return; + char buf[1024]; + va_list ap; + va_start(ap, szFormat); + vsnprintf(buf, sizeof(buf), szFormat, ap); + va_end(ap); +#ifdef __PS3__ + unsigned int writelen; + sys_tty_write(SYS_TTYP_USER1 + ( user - 1 ), buf, strlen(buf), &writelen ); +#elif defined __PSVITA__ + switch(user) + { + case 0: + { + SceUID tty2 = sceIoOpen("tty2:", SCE_O_WRONLY, 0); + if(tty2>=0) + { + std::string string1(buf); + sceIoWrite(tty2, string1.c_str(), string1.length()); + sceIoClose(tty2); + } + } + break; + case 1: + { + SceUID tty3 = sceIoOpen("tty3:", SCE_O_WRONLY, 0); + if(tty3>=0) + { + std::string string1(buf); + sceIoWrite(tty3, string1.c_str(), string1.length()); + sceIoClose(tty3); + } + } + break; + default: + OutputDebugStringA(buf); + break; + } +#else + OutputDebugStringA(buf); +#endif +#ifndef _XBOX + if(user == USER_UI) + { + ui.logDebugString(buf); + } +#endif +#endif +} + +LPCWSTR CMinecraftApp::GetString(int iID) +{ + //return L"Değişiklikler ve Yenilikler"; + //return L"ÕÕÕÕÖÖÖÖ"; + return app.m_stringTable->getString(iID); +} + +void CMinecraftApp::SetAction(int iPad, eXuiAction action, LPVOID param) +{ + if(m_eXuiAction[iPad] == eAppAction_ExitWorldCapturedThumbnail && action != eAppAction_Idle) + { + app.DebugPrintf("Invalid change of App action for pad %d from %d to %d, ignoring\n", iPad, m_eXuiAction[iPad], action); + } + else + { + app.DebugPrintf("Changing App action for pad %d from %d to %d\n", iPad, m_eXuiAction[iPad], action); + m_eXuiAction[iPad]=action; + m_eXuiActionParam[iPad] = param; + } +} + +bool CMinecraftApp::IsAppPaused() +{ +#if defined(_XBOX_ONE) || defined(__ORBIS__) + bool paused = m_bIsAppPaused; + EnterCriticalSection(&m_saveNotificationCriticalSection); + if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 ) + { + paused |= m_saveNotificationDepth > 0; + } + LeaveCriticalSection(&m_saveNotificationCriticalSection); + return paused; +#else + return m_bIsAppPaused; +#endif +} + +void CMinecraftApp::SetAppPaused(bool val) +{ + m_bIsAppPaused = val; +} + +void CMinecraftApp::HandleButtonPresses() +{ + for(int i=0;i<4;i++) + { + HandleButtonPresses(i); + } +} + +void CMinecraftApp::HandleButtonPresses(int iPad) +{ + +// // test an update of the profile data +// void *pData=ProfileManager.GetGameDefinedProfileData(iPad); +// +// unsigned char *pchData= (unsigned char *)pData; +// int iCount=0; +// for(int i=0;i player,bool bNavigateBack) +{ + bool success = true; + + InventoryScreenInput* initData = new InventoryScreenInput(); + initData->player = player; + initData->bNavigateBack=bNavigateBack; + initData->iPad = iPad; + + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_InventoryMenu,initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_InventoryMenu,initData); + } + + return success; +} + +bool CMinecraftApp::LoadCreativeMenu(int iPad,shared_ptr player,bool bNavigateBack) +{ + bool success = true; + + InventoryScreenInput* initData = new InventoryScreenInput(); + initData->player = player; + initData->bNavigateBack=bNavigateBack; + initData->iPad = iPad; + + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_CreativeMenu,initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_CreativeMenu,initData); + } + + return success; +} + +bool CMinecraftApp::LoadCrafting2x2Menu(int iPad,shared_ptr player) +{ + bool success = true; + + CraftingPanelScreenInput* initData = new CraftingPanelScreenInput(); + initData->player = player; + initData->iContainerType=RECIPE_TYPE_2x2; + initData->iPad = iPad; + initData->x = 0; + initData->y = 0; + initData->z = 0; + + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_Crafting2x2Menu, initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_Crafting2x2Menu, initData); + } + + return success; +} + +bool CMinecraftApp::LoadCrafting3x3Menu(int iPad,shared_ptr player, int x, int y, int z) +{ + bool success = true; + + CraftingPanelScreenInput* initData = new CraftingPanelScreenInput(); + initData->player = player; + initData->iContainerType=RECIPE_TYPE_3x3; + initData->iPad = iPad; + initData->x = x; + initData->y = y; + initData->z = z; + + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_Crafting3x3Menu, initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_Crafting3x3Menu, initData); + } + + return success; +} + +bool CMinecraftApp::LoadEnchantingMenu(int iPad,shared_ptr inventory, int x, int y, int z, Level *level) +{ + bool success = true; + + EnchantingScreenInput* initData = new EnchantingScreenInput(); + initData->inventory = inventory; + initData->level = level; + initData->x = x; + initData->y = y; + initData->z = z; + initData->iPad = iPad; + + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_EnchantingMenu, initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_EnchantingMenu, initData); + } + + return success; +} + +bool CMinecraftApp::LoadFurnaceMenu(int iPad,shared_ptr inventory, shared_ptr furnace) +{ + bool success = true; + + FurnaceScreenInput* initData = new FurnaceScreenInput(); + + initData->furnace = furnace; + initData->inventory = inventory; + initData->iPad = iPad; + + // Load the scene. + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_FurnaceMenu, initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_FurnaceMenu, initData); + } + + return success; +} + +bool CMinecraftApp::LoadBrewingStandMenu(int iPad,shared_ptr inventory, shared_ptr brewingStand) +{ + bool success = true; + + BrewingScreenInput* initData = new BrewingScreenInput(); + + initData->brewingStand = brewingStand; + initData->inventory = inventory; + initData->iPad = iPad; + + // Load the scene. + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_BrewingStandMenu, initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_BrewingStandMenu, initData); + } + + return success; +} + + +bool CMinecraftApp::LoadContainerMenu(int iPad,shared_ptr inventory, shared_ptr container) +{ + bool success = true; + + ContainerScreenInput* initData = new ContainerScreenInput(); + + initData->inventory = inventory; + initData->container = container; + initData->iPad = iPad; + + // Load the scene. + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + + bool bLargeChest = (initData->container->getContainerSize() > 3*9)?true:false; + if(bLargeChest) + { + success = ui.NavigateToScene(iPad,eUIScene_LargeContainerMenu,initData); + } + else + { + success = ui.NavigateToScene(iPad,eUIScene_ContainerMenu,initData); + } + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_ContainerMenu,initData); + } + + return success; +} + +bool CMinecraftApp::LoadTrapMenu(int iPad,shared_ptr inventory, shared_ptr trap) +{ + bool success = true; + + TrapScreenInput* initData = new TrapScreenInput(); + + initData->inventory = inventory; + initData->trap = trap; + initData->iPad = iPad; + + // Load the scene. + if(app.GetLocalPlayerCount()>1) + { + initData->bSplitscreen=true; + success = ui.NavigateToScene(iPad,eUIScene_DispenserMenu, initData); + } + else + { + initData->bSplitscreen=false; + success = ui.NavigateToScene(iPad,eUIScene_DispenserMenu, initData); + } + + return success; +} + +bool CMinecraftApp::LoadSignEntryMenu(int iPad,shared_ptr sign) +{ + bool success = true; + + SignEntryScreenInput* initData = new SignEntryScreenInput(); + + initData->sign = sign; + initData->iPad = iPad; + + success = ui.NavigateToScene(iPad,eUIScene_SignEntryMenu, initData); + + delete initData; + + return success; +} + +bool CMinecraftApp::LoadRepairingMenu(int iPad,shared_ptr inventory, Level *level, int x, int y, int z) +{ + bool success = true; + + AnvilScreenInput *initData = new AnvilScreenInput(); + initData->inventory = inventory; + initData->level = level; + initData->x = x; + initData->y = y; + initData->z = z; + initData->iPad = iPad; + if(app.GetLocalPlayerCount()>1) initData->bSplitscreen=true; + else initData->bSplitscreen=false; + + success = ui.NavigateToScene(iPad,eUIScene_AnvilMenu, initData); + + return success; +} + +bool CMinecraftApp::LoadTradingMenu(int iPad, shared_ptr inventory, shared_ptr trader, Level *level) +{ + bool success = true; + + TradingScreenInput *initData = new TradingScreenInput(); + initData->inventory = inventory; + initData->trader = trader; + initData->level = level; + initData->iPad = iPad; + if(app.GetLocalPlayerCount()>1) initData->bSplitscreen=true; + else initData->bSplitscreen=false; + + success = ui.NavigateToScene(iPad,eUIScene_TradingMenu, initData); + + return success; +} + + +////////////////////////////////////////////// +// GAME SETTINGS +////////////////////////////////////////////// +void CMinecraftApp::InitGameSettings() +{ + for(int i=0;ibSettingsChanged=false; + + //SetDefaultGameSettings(i); - done on a callback from the profile manager + + // 4J-PB - adding in for Windows & PS3 to set the defaults for the joypad +#if defined _WINDOWS64// || defined __PSVITA__ + C_4JProfile::PROFILESETTINGS *pProfileSettings=ProfileManager.GetDashboardProfileSettings(i); + // clear this for now - it will come from reading the system values + memset(pProfileSettings,0,sizeof(C_4JProfile::PROFILESETTINGS)); + SetDefaultOptions(pProfileSettings,i); +#elif defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__ + C4JStorage::PROFILESETTINGS *pProfileSettings=StorageManager.GetDashboardProfileSettings(i); + // 4J-PB - don't cause an options write to happen here + SetDefaultOptions(pProfileSettings,i,false); + +#endif + } +} + +#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) +int CMinecraftApp::SetDefaultOptions(C4JStorage::PROFILESETTINGS *pSettings,const int iPad,bool bWriteProfile) +#else +int CMinecraftApp::SetDefaultOptions(C_4JProfile::PROFILESETTINGS *pSettings,const int iPad) +#endif +{ + SetGameSettings(iPad,eGameSetting_MusicVolume,DEFAULT_VOLUME_LEVEL); + SetGameSettings(iPad,eGameSetting_SoundFXVolume,DEFAULT_VOLUME_LEVEL); + SetGameSettings(iPad,eGameSetting_Gamma,100); + + // 4J-PB - Don't reset the difficult level if we're in-game + if(Minecraft::GetInstance()->level==NULL) + { + app.DebugPrintf("SetDefaultOptions - Difficulty = 1\n"); + SetGameSettings(iPad,eGameSetting_Difficulty,1); + } + SetGameSettings(iPad,eGameSetting_Sensitivity_InGame,100); + SetGameSettings(iPad,eGameSetting_ViewBob,1); + SetGameSettings(iPad,eGameSetting_ControlScheme,0); + SetGameSettings(iPad,eGameSetting_ControlInvertLook,(pSettings->iYAxisInversion!=0)?1:0); + SetGameSettings(iPad,eGameSetting_ControlSouthPaw,pSettings->bSwapSticks?1:0); + SetGameSettings(iPad,eGameSetting_SplitScreenVertical,0); + SetGameSettings(iPad,eGameSetting_GamertagsVisible,1); + + // Interim TU 1.6.6 + SetGameSettings(iPad,eGameSetting_Sensitivity_InMenu,100); + SetGameSettings(iPad,eGameSetting_DisplaySplitscreenGamertags,1); + SetGameSettings(iPad,eGameSetting_Hints,1); + SetGameSettings(iPad,eGameSetting_Autosave,2); + SetGameSettings(iPad,eGameSetting_Tooltips,1); + SetGameSettings(iPad,eGameSetting_InterfaceOpacity,80); + + // TU 5 + SetGameSettings(iPad,eGameSetting_Clouds,1); + SetGameSettings(iPad,eGameSetting_Online,1); + SetGameSettings(iPad,eGameSetting_InviteOnly,0); + SetGameSettings(iPad,eGameSetting_FriendsOfFriends,1); + + // default the update changes message to zero + // 4J-PB - We'll only display the message if the profile is pre-TU5 + //SetGameSettings(iPad,eGameSetting_DisplayUpdateMessage,0); + + // TU 6 + SetGameSettings(iPad,eGameSetting_BedrockFog,0); + SetGameSettings(iPad,eGameSetting_DisplayHUD,1); + SetGameSettings(iPad,eGameSetting_DisplayHand,1); + + // TU 7 + SetGameSettings(iPad,eGameSetting_CustomSkinAnim,1); + + // TU 9 + SetGameSettings(iPad,eGameSetting_DeathMessages,1); + SetGameSettings(iPad,eGameSetting_UISize,1); + SetGameSettings(iPad,eGameSetting_UISizeSplitscreen,2); + SetGameSettings(iPad,eGameSetting_AnimatedCharacter,1); + + // TU 12 + GameSettingsA[iPad]->ucCurrentFavoriteSkinPos=0; + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + + // TU 13 + GameSettingsA[iPad]->uiMashUpPackWorldsDisplay=0xFFFFFFFF; + + // 4J-PB - leave these in, or remove from everywhere they are referenced! + // Although probably best to leave in unless we split the profile settings into platform specific classes - having different meaning per platform for the same bitmask could get confusing +//#ifdef __PS3__ + // PS3DEC13 + SetGameSettings(iPad,eGameSetting_PS3_EULA_Read,0); // EULA not read + + // PS3 1.05 - added Greek + GameSettingsA[iPad]->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language +//#endif + +#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + GameSettingsA[iPad]->bSettingsChanged=bWriteProfile; +#endif + + return 0; +} + +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) +int CMinecraftApp::DefaultOptionsCallback(LPVOID pParam,C4JStorage::PROFILESETTINGS *pSettings, const int iPad) +#else +int CMinecraftApp::DefaultOptionsCallback(LPVOID pParam,C_4JProfile::PROFILESETTINGS *pSettings, const int iPad) +#endif +{ + CMinecraftApp *pApp=(CMinecraftApp *)pParam; + + // flag the default options to be set + + pApp->DebugPrintf("Setting default options for player %d", iPad); + pApp->SetAction(iPad,eAppAction_SetDefaultOptions, (LPVOID)pSettings); + //pApp->SetDefaultOptions(pSettings,iPad); + + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + //pApp->CheckGameSettingsChanged(); + + return 0; +} + +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + +#ifdef __ORBIS__ +int CMinecraftApp::OptionsDataCallback(LPVOID pParam,int iPad,unsigned short usVersion,C4JStorage::eOptionsCallback eStatus,int iBlocksRequired) +{ + CMinecraftApp *pApp=(CMinecraftApp *)pParam; + pApp->m_eOptionsStatusA[iPad]=eStatus; + pApp->m_eOptionsBlocksRequiredA[iPad]=iBlocksRequired; + return 0; +} + +int CMinecraftApp::GetOptionsBlocksRequired(int iPad) +{ + return m_eOptionsBlocksRequiredA[iPad]; +} + +#else +int CMinecraftApp::OptionsDataCallback(LPVOID pParam,int iPad,unsigned short usVersion,C4JStorage::eOptionsCallback eStatus) +{ + CMinecraftApp *pApp=(CMinecraftApp *)pParam; + pApp->m_eOptionsStatusA[iPad]=eStatus; + return 0; +} +#endif + +C4JStorage::eOptionsCallback CMinecraftApp::GetOptionsCallbackStatus(int iPad) +{ + return m_eOptionsStatusA[iPad]; +} + +void CMinecraftApp::SetOptionsCallbackStatus(int iPad, C4JStorage::eOptionsCallback eStatus) +{ + m_eOptionsStatusA[iPad]=eStatus; +} +#endif + +int CMinecraftApp::OldProfileVersionCallback(LPVOID pParam,unsigned char *pucData, const unsigned short usVersion, const int iPad) +{ + // check what needs to be done with this version to update to the current one + + switch(usVersion) + { +#ifdef _XBOX + case PROFILE_VERSION_1: + case PROFILE_VERSION_2: + // need to fill in values for the new profile data. No need to save the profile - that'll happen if they get changed, or if the auto save for the profile kicks in + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + pGameSettings->ucMenuSensitivity=100; //eGameSetting_Sensitivity_InMenu + pGameSettings->ucInterfaceOpacity=80; //eGameSetting_Sensitivity_InMenu + pGameSettings->usBitmaskValues|=0x0200; //eGameSetting_DisplaySplitscreenGamertags - on + pGameSettings->usBitmaskValues|=0x0400; //eGameSetting_Hints - on + pGameSettings->usBitmaskValues|=0x1000; //eGameSetting_Autosave - 2 + pGameSettings->usBitmaskValues|=0x8000; //eGameSetting_Tooltips - on + + // 4J-PB - Let's also award all the achievements they have again because of the profile bug that seemed to stop the awards of some + // Changing this to check the system achievements at sign-in and award any that the game says we have and the system says we haven't + //ProfileManager.ReAwardAchievements(iPad); + + pGameSettings->uiBitmaskValues=0L; // reset + pGameSettings->uiBitmaskValues|=GAMESETTING_CLOUDS; //eGameSetting_Clouds - on + pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE; //eGameSetting_GameSetting_Online - on + //eGameSetting_GameSetting_Invite - off + pGameSettings->uiBitmaskValues|=GAMESETTING_FRIENDSOFFRIENDS; //eGameSetting_GameSetting_FriendsOfFriends - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + // TU6 + pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG; //eGameSetting_BedrockFog - off + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD; //eGameSetting_DisplayHUD - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND; //eGameSetting_DisplayHand - on + // TU7 + pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM; //eGameSetting_CustomSkinAnim - on + // TU9 + pGameSettings->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; //eGameSetting_DeathMessages - on + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2 + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3 + pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + } + break; + case PROFILE_VERSION_3: + + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + pGameSettings->uiBitmaskValues=0L; // reset + pGameSettings->uiBitmaskValues|=GAMESETTING_CLOUDS; //eGameSetting_Clouds - on + pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE; //eGameSetting_GameSetting_Online - on + //eGameSetting_GameSetting_Invite - off + pGameSettings->uiBitmaskValues|=GAMESETTING_FRIENDSOFFRIENDS; //eGameSetting_GameSetting_FriendsOfFriends - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + // TU6 + pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG; //eGameSetting_BedrockFog - off + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD; //eGameSetting_DisplayHUD - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND; //eGameSetting_DisplayHand - on + // TU7 + pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM; //eGameSetting_CustomSkinAnim - on + // TU9 + pGameSettings->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; //eGameSetting_DeathMessages - on + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2 + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3 + pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + } + break; + case PROFILE_VERSION_4: + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + + pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG; //eGameSetting_BedrockFog - off + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD; //eGameSetting_DisplayHUD - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND; //eGameSetting_DisplayHand - on + // TU7 + pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM; //eGameSetting_CustomSkinAnim - on + // TU9 + pGameSettings->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; //eGameSetting_DeathMessages - on + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2 + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3 + pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on + + // Set the online flag to on, so it's not saved if a game starts offline when the user didn't change it to be offline (xbox disconnected from LIVE) + pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE; //eGameSetting_GameSetting_Online - on + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + } + + break; + case PROFILE_VERSION_5: + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + + // reset the display new message counter + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + // TU7 + pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM; //eGameSetting_CustomSkinAnim - on + // TU9 + pGameSettings->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; //eGameSetting_DeathMessages - on + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2 + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3 + pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on + // Set the online flag to on, so it's not saved if a game starts offline when the user didn't change it to be offline (xbox disconnected from LIVE) + pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE; //eGameSetting_GameSetting_Online - on + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + + } + + break; + case PROFILE_VERSION_6: + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + + // Added gui size for splitscreen and fullscreen + // Added death messages toggle + + // reset the display new message counter + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + // TU9 + pGameSettings->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; //eGameSetting_DeathMessages - on + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2 + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3 + pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on + // Set the online flag to on, so it's not saved if a game starts offline when the user didn't change it to be offline (xbox disconnected from LIVE) + pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE; //eGameSetting_GameSetting_Online - on + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + + } + + break; + + case PROFILE_VERSION_7: + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + // reset the display new message counter + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + + } + break; +#endif + case PROFILE_VERSION_8: + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + // reset the display new message counter + //pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3DEC13 + pGameSettings->uiBitmaskValues&=~GAMESETTING_PS3EULAREAD; //eGameSetting_PS3_EULA_Read - off + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + } + break; + case PROFILE_VERSION_9: + // PS3DEC13 + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + pGameSettings->uiBitmaskValues&=~GAMESETTING_PS3EULAREAD; //eGameSetting_PS3_EULA_Read - off + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + } + break; + case PROFILE_VERSION_10: + { + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + } + break; + + default: + { + // This might be from a version during testing of new profile updates + app.DebugPrintf("Don't know what to do with this profile version!\n"); + #ifndef _CONTENT_PACKAGE + // __debugbreak(); + #endif + + GAME_SETTINGS *pGameSettings=(GAME_SETTINGS *)pucData; + pGameSettings->ucMenuSensitivity=100; //eGameSetting_Sensitivity_InMenu + pGameSettings->ucInterfaceOpacity=80; //eGameSetting_Sensitivity_InMenu + pGameSettings->usBitmaskValues|=0x0200; //eGameSetting_DisplaySplitscreenGamertags - on + pGameSettings->usBitmaskValues|=0x0400; //eGameSetting_Hints - on + pGameSettings->usBitmaskValues|=0x1000; //eGameSetting_Autosave - 2 + pGameSettings->usBitmaskValues|=0x8000; //eGameSetting_Tooltips - on + + pGameSettings->uiBitmaskValues=0L; // reset + pGameSettings->uiBitmaskValues|=GAMESETTING_CLOUDS; //eGameSetting_Clouds - on + pGameSettings->uiBitmaskValues|=GAMESETTING_ONLINE; //eGameSetting_GameSetting_Online - on + //eGameSetting_GameSetting_Invite - off + pGameSettings->uiBitmaskValues|=GAMESETTING_FRIENDSOFFRIENDS; //eGameSetting_GameSetting_FriendsOfFriends - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYUPDATEMSG; //eGameSetting_DisplayUpdateMessage (counter) + pGameSettings->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG; //eGameSetting_BedrockFog - off + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHUD; //eGameSetting_DisplayHUD - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DISPLAYHAND; //eGameSetting_DisplayHand - on + pGameSettings->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM; //eGameSetting_CustomSkinAnim - on + pGameSettings->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; //eGameSetting_DeathMessages - on + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE&0x00000800); // uisize 2 + pGameSettings->uiBitmaskValues|=(GAMESETTING_UISIZE_SPLITSCREEN&0x00004000); // splitscreen ui size 3 + pGameSettings->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; //eGameSetting_AnimatedCharacter - on + // TU12 + // favorite skins added, but only set in TU12 - set to FFs + for(int i=0;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } + pGameSettings->ucCurrentFavoriteSkinPos=0; + // Added a bitmask in TU13 to enable/disable display of the Mash-up pack worlds in the saves list + pGameSettings->uiMashUpPackWorldsDisplay = 0xFFFFFFFF; + + // PS3DEC13 + pGameSettings->uiBitmaskValues&=~GAMESETTING_PS3EULAREAD; //eGameSetting_PS3_EULA_Read - off + + // PS3 1.05 - added Greek + pGameSettings->ucLanguage = MINECRAFT_LANGUAGE_DEFAULT; // use the system language + + } + break; + } + + return 0; +} + +void CMinecraftApp::ApplyGameSettingsChanged(int iPad) +{ + ActionGameSettings(iPad,eGameSetting_MusicVolume ); + ActionGameSettings(iPad,eGameSetting_SoundFXVolume ); + ActionGameSettings(iPad,eGameSetting_Gamma ); + ActionGameSettings(iPad,eGameSetting_Difficulty ); + ActionGameSettings(iPad,eGameSetting_Sensitivity_InGame ); + ActionGameSettings(iPad,eGameSetting_ViewBob ); + ActionGameSettings(iPad,eGameSetting_ControlScheme ); + ActionGameSettings(iPad,eGameSetting_ControlInvertLook); + ActionGameSettings(iPad,eGameSetting_ControlSouthPaw); + ActionGameSettings(iPad,eGameSetting_SplitScreenVertical); + ActionGameSettings(iPad,eGameSetting_GamertagsVisible); + + // Interim TU 1.6.6 + ActionGameSettings(iPad,eGameSetting_Sensitivity_InMenu ); + ActionGameSettings(iPad,eGameSetting_DisplaySplitscreenGamertags); + ActionGameSettings(iPad,eGameSetting_Hints); + ActionGameSettings(iPad,eGameSetting_InterfaceOpacity); + ActionGameSettings(iPad,eGameSetting_Tooltips); + + ActionGameSettings(iPad,eGameSetting_Clouds); + ActionGameSettings(iPad,eGameSetting_BedrockFog); + ActionGameSettings(iPad,eGameSetting_DisplayHUD); + ActionGameSettings(iPad,eGameSetting_DisplayHand); + ActionGameSettings(iPad,eGameSetting_CustomSkinAnim); + ActionGameSettings(iPad,eGameSetting_DeathMessages); + ActionGameSettings(iPad,eGameSetting_UISize); + ActionGameSettings(iPad,eGameSetting_UISizeSplitscreen); + ActionGameSettings(iPad,eGameSetting_AnimatedCharacter); + + ActionGameSettings(iPad,eGameSetting_PS3_EULA_Read); + +} + +void CMinecraftApp::ActionGameSettings(int iPad,eGameSetting eVal) +{ + Minecraft *pMinecraft=Minecraft::GetInstance(); + switch(eVal) + { + case eGameSetting_MusicVolume: + if(iPad==ProfileManager.GetPrimaryPad()) + { + pMinecraft->options->set(Options::Option::MUSIC,((float)GameSettingsA[iPad]->ucMusicVolume)/100.0f); + } + break; + case eGameSetting_SoundFXVolume: + if(iPad==ProfileManager.GetPrimaryPad()) + { + pMinecraft->options->set(Options::Option::SOUND,((float)GameSettingsA[iPad]->ucSoundFXVolume)/100.0f); + } + break; + case eGameSetting_Gamma: + if(iPad==ProfileManager.GetPrimaryPad()) + { + // ucGamma range is 0-100, UpdateGamma is 0 - 32768 + float fVal=((float)GameSettingsA[iPad]->ucGamma)*327.68f; + RenderManager.UpdateGamma((unsigned short)fVal); +#ifdef _WINDOWS64 + extern void Windows64_UpdateGamma(unsigned short); + Windows64_UpdateGamma((unsigned short)fVal); +#endif + } + + break; + case eGameSetting_Difficulty: + if(iPad==ProfileManager.GetPrimaryPad()) + { + pMinecraft->options->toggle(Options::Option::DIFFICULTY,GameSettingsA[iPad]->usBitmaskValues&0x03); + app.DebugPrintf("Difficulty toggle to %d\n",GameSettingsA[iPad]->usBitmaskValues&0x03); + + // Update the Game Host setting + app.SetGameHostOption(eGameHostOption_Difficulty,pMinecraft->options->difficulty); + + // send this to the other players if we are in-game + bool bInGame=pMinecraft->level!=NULL; + + // Game Host only (and for now we can't change the diff while in game, so this shouldn't happen) + if(bInGame && g_NetworkManager.IsHost() && (iPad==ProfileManager.GetPrimaryPad())) + { + app.SetXuiServerAction(iPad,eXuiServerAction_ServerSettingChanged_Difficulty); + } + } + else + { + app.DebugPrintf("NOT ACTIONING DIFFICULTY - Primary pad is %d, This pad is %d\n",ProfileManager.GetPrimaryPad(),iPad); + } + + break; + case eGameSetting_Sensitivity_InGame: + // 4J-PB - we don't use the options value + // tell the input that we've changed the sensitivity - range of the slider is 0 to 200, default is 100 + pMinecraft->options->set(Options::Option::SENSITIVITY,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); + //InputManager.SetJoypadSensitivity(iPad,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); + + break; + case eGameSetting_ViewBob: + // 4J-PB - not handled here any more - it's read from the gamesettings per player + //pMinecraft->options->toggle(Options::Option::VIEW_BOBBING,GameSettingsA[iPad]->usBitmaskValues&0x04); + break; + case eGameSetting_ControlScheme: + InputManager.SetJoypadMapVal(iPad,(GameSettingsA[iPad]->usBitmaskValues&0x30)>>4); + break; + + case eGameSetting_ControlInvertLook: + // Nothing specific to do for this setting. + break; + + case eGameSetting_ControlSouthPaw: + // What is the setting? + if ( GameSettingsA[iPad]->usBitmaskValues & 0x80 ) + { + // Southpaw. + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_LX, AXIS_MAP_RX ); + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_LY, AXIS_MAP_RY ); + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_RX, AXIS_MAP_LX ); + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_RY, AXIS_MAP_LY ); + InputManager.SetJoypadStickTriggerMap( iPad, TRIGGER_MAP_0, TRIGGER_MAP_1 ); + InputManager.SetJoypadStickTriggerMap( iPad, TRIGGER_MAP_1, TRIGGER_MAP_0 ); + } + else + { + // Right handed. + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_LX, AXIS_MAP_LX ); + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_LY, AXIS_MAP_LY ); + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_RX, AXIS_MAP_RX ); + InputManager.SetJoypadStickAxisMap( iPad, AXIS_MAP_RY, AXIS_MAP_RY ); + InputManager.SetJoypadStickTriggerMap( iPad, TRIGGER_MAP_0, TRIGGER_MAP_0 ); + InputManager.SetJoypadStickTriggerMap( iPad, TRIGGER_MAP_1, TRIGGER_MAP_1 ); + } + break; + case eGameSetting_SplitScreenVertical: + if(iPad==ProfileManager.GetPrimaryPad()) + { + pMinecraft->updatePlayerViewportAssignments(); + } + break; + case eGameSetting_GamertagsVisible: + { + bool bInGame=pMinecraft->level!=NULL; + + // Game Host only + if(bInGame && g_NetworkManager.IsHost() && (iPad==ProfileManager.GetPrimaryPad())) + { + // Update the Game Host setting if you are the host and you are in-game + app.SetGameHostOption(eGameHostOption_Gamertags,((GameSettingsA[iPad]->usBitmaskValues&0x0008)!=0)?1:0); + app.SetXuiServerAction(iPad,eXuiServerAction_ServerSettingChanged_Gamertags); + + PlayerList *players = MinecraftServer::getInstance()->getPlayerList(); + for(AUTO_VAR(it3, players->players.begin()); it3 != players->players.end(); ++it3) + { + shared_ptr decorationPlayer = *it3; + decorationPlayer->setShowOnMaps((app.GetGameHostOption(eGameHostOption_Gamertags)!=0)?true:false); + } + } + } + break; +// Interim TU 1.6.6 + case eGameSetting_Sensitivity_InMenu: + // 4J-PB - we don't use the options value + // tell the input that we've changed the sensitivity - range of the slider is 0 to 200, default is 100 + //pMinecraft->options->set(Options::Option::SENSITIVITY,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); + //InputManager.SetJoypadSensitivity(iPad,((float)GameSettingsA[iPad]->ucSensitivity)/100.0f); + + break; + + case eGameSetting_DisplaySplitscreenGamertags: + for( BYTE idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if(pMinecraft->localplayers[idx] != NULL) + { + if(pMinecraft->localplayers[idx]->m_iScreenSection==C4JRender::VIEWPORT_TYPE_FULLSCREEN) + { + ui.DisplayGamertag(idx,false); + } + else + { + ui.DisplayGamertag(idx,true); + } + } + } + + break; + case eGameSetting_InterfaceOpacity: + // update the tooltips display + ui.RefreshTooltips( iPad); + + break; + case eGameSetting_Hints: + //nothing to do here + break; + case eGameSetting_Tooltips: + if((GameSettingsA[iPad]->usBitmaskValues&0x8000)!=0) + { + ui.SetEnableTooltips(iPad,TRUE); + } + else + { + ui.SetEnableTooltips(iPad,FALSE); + } + break; + case eGameSetting_Clouds: + //nothing to do here + break; + case eGameSetting_Online: + //nothing to do here + break; + case eGameSetting_InviteOnly: + //nothing to do here + break; + case eGameSetting_FriendsOfFriends: + //nothing to do here + break; + case eGameSetting_BedrockFog: + { + bool bInGame=pMinecraft->level!=NULL; + + // Game Host only + if(bInGame && g_NetworkManager.IsHost() && (iPad==ProfileManager.GetPrimaryPad())) + { + // Update the Game Host setting if you are the host and you are in-game + app.SetGameHostOption(eGameHostOption_BedrockFog,GetGameSettings(iPad,eGameSetting_BedrockFog)?1:0); + app.SetXuiServerAction(iPad,eXuiServerAction_ServerSettingChanged_BedrockFog); + } + } + break; + case eGameSetting_DisplayHUD: + //nothing to do here + break; + case eGameSetting_DisplayHand: + //nothing to do here + break; + case eGameSetting_CustomSkinAnim: + //nothing to do here + break; + case eGameSetting_DeathMessages: + //nothing to do here + break; + case eGameSetting_UISize: + //nothing to do here + break; + case eGameSetting_UISizeSplitscreen: + //nothing to do here + break; + case eGameSetting_AnimatedCharacter: + //nothing to do here + break; + case eGameSetting_PS3_EULA_Read: + //nothing to do here + break; + case eGameSetting_PSVita_NetworkModeAdhoc: + //nothing to do here + break; + } +} + +void CMinecraftApp::SetPlayerSkin(int iPad,const wstring &name) +{ + DWORD skinId = app.getSkinIdFromPath(name); + + SetPlayerSkin(iPad,skinId); +} + +void CMinecraftApp::SetPlayerSkin(int iPad,DWORD dwSkinId) +{ + DebugPrintf("Setting skin for %d to %08X\n", iPad, dwSkinId); + + GameSettingsA[iPad]->dwSelectedSkin = dwSkinId; + GameSettingsA[iPad]->bSettingsChanged = true; + + TelemetryManager->RecordSkinChanged(iPad, GameSettingsA[iPad]->dwSelectedSkin); + + if(Minecraft::GetInstance()->localplayers[iPad]!=NULL) Minecraft::GetInstance()->localplayers[iPad]->setAndBroadcastCustomSkin(dwSkinId); +} + + +wstring CMinecraftApp::GetPlayerSkinName(int iPad) +{ + return app.getSkinPathFromId(GameSettingsA[iPad]->dwSelectedSkin); +} + +DWORD CMinecraftApp::GetPlayerSkinId(int iPad) +{ + // 4J-PB -check the user has rights to use this skin - they may have had at some point but the entitlement has been removed. + DLCPack *Pack=NULL; + DLCSkinFile *skinFile=NULL; + DWORD dwSkin=GameSettingsA[iPad]->dwSelectedSkin; + wchar_t chars[256]; + + if( GET_IS_DLC_SKIN_FROM_BITMASK(dwSkin) ) + { + // 4J Stu - DLC skins are numbered using decimal rather than hex to make it easier to number manually + swprintf(chars, 256, L"dlcskin%08d.png", GET_DLC_SKIN_ID_FROM_BITMASK(dwSkin)); + + Pack=app.m_dlcManager.getPackContainingSkin(chars); + + if(Pack) + { + skinFile = Pack->getSkinFile(chars); + + bool bSkinIsFree = skinFile->getParameterAsBool( DLCManager::e_DLCParamType_Free ); + bool bLicensed = Pack->hasPurchasedFile( DLCManager::e_DLCType_Skin, skinFile->getPath() ); + + if(bSkinIsFree || bLicensed) + { + return dwSkin; + } + else + { + return 0; + } + } + } + + + return dwSkin; +} + + DWORD CMinecraftApp::GetAdditionalModelParts(int iPad) + { + return m_dwAdditionalModelParts[iPad]; + } + + +void CMinecraftApp::SetPlayerCape(int iPad,const wstring &name) +{ + DWORD capeId = Player::getCapeIdFromPath(name); + + SetPlayerCape(iPad,capeId); +} + +void CMinecraftApp::SetPlayerCape(int iPad,DWORD dwCapeId) +{ + DebugPrintf("Setting cape for %d to %08X\n", iPad, dwCapeId); + + GameSettingsA[iPad]->dwSelectedCape = dwCapeId; + GameSettingsA[iPad]->bSettingsChanged = true; + + //SentientManager.RecordSkinChanged(iPad, GameSettingsA[iPad]->dwSelectedSkin); + + if(Minecraft::GetInstance()->localplayers[iPad]!=NULL) Minecraft::GetInstance()->localplayers[iPad]->setAndBroadcastCustomCape(dwCapeId); +} + +wstring CMinecraftApp::GetPlayerCapeName(int iPad) +{ + return Player::getCapePathFromId(GameSettingsA[iPad]->dwSelectedCape); +} + +DWORD CMinecraftApp::GetPlayerCapeId(int iPad) +{ + return GameSettingsA[iPad]->dwSelectedCape; +} + +void CMinecraftApp::SetPlayerFavoriteSkin(int iPad, int iIndex,unsigned int uiSkinID) +{ + DebugPrintf("Setting favorite skin for %d to %08X\n", iPad, uiSkinID); + + GameSettingsA[iPad]->uiFavoriteSkinA[iIndex] = uiSkinID; + GameSettingsA[iPad]->bSettingsChanged = true; +} + +unsigned int CMinecraftApp::GetPlayerFavoriteSkin(int iPad,int iIndex) +{ + return GameSettingsA[iPad]->uiFavoriteSkinA[iIndex]; +} + +unsigned char CMinecraftApp::GetPlayerFavoriteSkinsPos(int iPad) +{ + return GameSettingsA[iPad]->ucCurrentFavoriteSkinPos; +} + +void CMinecraftApp::SetPlayerFavoriteSkinsPos(int iPad, int iPos) +{ + GameSettingsA[iPad]->ucCurrentFavoriteSkinPos=(unsigned char)iPos; + GameSettingsA[iPad]->bSettingsChanged = true; +} + +unsigned int CMinecraftApp::GetPlayerFavoriteSkinsCount(int iPad) +{ + unsigned int uiCount=0; + for(int i=0;iuiFavoriteSkinA[i]!=0xFFFFFFFF) + { + uiCount++; + } + else + { + break; + } + } + return uiCount; +} + +void CMinecraftApp::ValidateFavoriteSkins(int iPad) +{ + unsigned int uiCount=GetPlayerFavoriteSkinsCount(iPad); + + // remove invalid skins + unsigned int uiValidSkin=0; + wchar_t chars[256]; + + for(unsigned int i=0;igetFile(DLCManager::e_DLCType_Skin,chars); + DLCSkinFile *pSkinFile = pDLCPack->getSkinFile(chars); + + if( pDLCPack->hasPurchasedFile(DLCManager::e_DLCType_Skin, L"") || (pSkinFile && pSkinFile->isFree())) + { + GameSettingsA[iPad]->uiFavoriteSkinA[uiValidSkin++]=GameSettingsA[iPad]->uiFavoriteSkinA[i]; + } + } + } + + for(unsigned int i=uiValidSkin;iuiFavoriteSkinA[i]=0xFFFFFFFF; + } +} + +// Mash-up pack worlds +void CMinecraftApp::HideMashupPackWorld(int iPad, unsigned int iMashupPackID) +{ + unsigned int uiPackID=iMashupPackID - 1024; // mash-up ids start at 1024 + GameSettingsA[iPad]->uiMashUpPackWorldsDisplay&=~(1<bSettingsChanged = true; +} + +void CMinecraftApp::SetMinecraftLanguage(int iPad, unsigned char ucLanguage) +{ + GameSettingsA[iPad]->ucLanguage = ucLanguage; + GameSettingsA[iPad]->bSettingsChanged = true; +} + +void CMinecraftApp::EnableMashupPackWorlds(int iPad) +{ + GameSettingsA[iPad]->uiMashUpPackWorldsDisplay=0xFFFFFFFF; + GameSettingsA[iPad]->bSettingsChanged = true; +} + +unsigned int CMinecraftApp::GetMashupPackWorlds(int iPad) +{ + return GameSettingsA[iPad]->uiMashUpPackWorldsDisplay; +} + +unsigned char CMinecraftApp::GetMinecraftLanguage(int iPad) +{ + // if there are no game settings read yet, return the default language + if(GameSettingsA[iPad]==NULL) + { + return 0; + } + else + { + return GameSettingsA[iPad]->ucLanguage; + } +} + +void CMinecraftApp::SetGameSettings(int iPad,eGameSetting eVal,unsigned char ucVal) +{ + //Minecraft *pMinecraft=Minecraft::GetInstance(); + + switch(eVal) + { + case eGameSetting_MusicVolume: + if(GameSettingsA[iPad]->ucMusicVolume!=ucVal) + { + GameSettingsA[iPad]->ucMusicVolume=ucVal; + if(iPad==ProfileManager.GetPrimaryPad()) + { + ActionGameSettings(iPad,eVal); + } + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_SoundFXVolume: + if(GameSettingsA[iPad]->ucSoundFXVolume!=ucVal) + { + GameSettingsA[iPad]->ucSoundFXVolume=ucVal; + if(iPad==ProfileManager.GetPrimaryPad()) + { + ActionGameSettings(iPad,eVal); + } + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_Gamma: + if(GameSettingsA[iPad]->ucGamma!=ucVal) + { + GameSettingsA[iPad]->ucGamma=ucVal; + if(iPad==ProfileManager.GetPrimaryPad()) + { + ActionGameSettings(iPad,eVal); + } + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_Difficulty: + if((GameSettingsA[iPad]->usBitmaskValues&0x03)!=(ucVal&0x03)) + { + GameSettingsA[iPad]->usBitmaskValues&=~0x03; + GameSettingsA[iPad]->usBitmaskValues|=ucVal&0x03; + if(iPad==ProfileManager.GetPrimaryPad()) + { + ActionGameSettings(iPad,eVal); + } + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_Sensitivity_InGame: + if(GameSettingsA[iPad]->ucSensitivity!=ucVal) + { + GameSettingsA[iPad]->ucSensitivity=ucVal; + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_ViewBob: + if((GameSettingsA[iPad]->usBitmaskValues&0x0004)!=((ucVal&0x01)<<2)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0004; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0004; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_ControlScheme: // bits 5 and 6 + if((GameSettingsA[iPad]->usBitmaskValues&0x30)!=((ucVal&0x03)<<4)) + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0030; + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=(ucVal&0x03)<<4; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + + case eGameSetting_ControlInvertLook: + if((GameSettingsA[iPad]->usBitmaskValues&0x0040)!=((ucVal&0x01)<<6)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0040; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0040; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + + case eGameSetting_ControlSouthPaw: + if((GameSettingsA[iPad]->usBitmaskValues&0x0080)!=((ucVal&0x01)<<7)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0080; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0080; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_SplitScreenVertical: + if((GameSettingsA[iPad]->usBitmaskValues&0x0100)!=((ucVal&0x01)<<8)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0100; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0100; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_GamertagsVisible: + if((GameSettingsA[iPad]->usBitmaskValues&0x0008)!=((ucVal&0x01)<<3)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0008; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0008; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + + // 4J-PB - Added for Interim TU for 1.6.6 + case eGameSetting_Sensitivity_InMenu: + if(GameSettingsA[iPad]->ucMenuSensitivity!=ucVal) + { + GameSettingsA[iPad]->ucMenuSensitivity=ucVal; + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_DisplaySplitscreenGamertags: + if((GameSettingsA[iPad]->usBitmaskValues&0x0200)!=((ucVal&0x01)<<9)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0200; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0200; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_Hints: + if((GameSettingsA[iPad]->usBitmaskValues&0x0400)!=((ucVal&0x01)<<10)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x0400; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x0400; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_Autosave: + if((GameSettingsA[iPad]->usBitmaskValues&0x7800)!=((ucVal&0x0F)<<11)) + { + GameSettingsA[iPad]->usBitmaskValues&=~0x7800; + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=(ucVal&0x0F)<<11; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + + case eGameSetting_Tooltips: + if((GameSettingsA[iPad]->usBitmaskValues&0x8000)!=((ucVal&0x01)<<15)) + { + if(ucVal!=0) + { + GameSettingsA[iPad]->usBitmaskValues|=0x8000; + } + else + { + GameSettingsA[iPad]->usBitmaskValues&=~0x8000; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_InterfaceOpacity: + if(GameSettingsA[iPad]->ucInterfaceOpacity!=ucVal) + { + GameSettingsA[iPad]->ucInterfaceOpacity=ucVal; + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + case eGameSetting_Clouds: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_CLOUDS)!=(ucVal&0x01)) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_CLOUDS; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_CLOUDS; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + + case eGameSetting_Online: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_ONLINE)!=(ucVal&0x01)<<1) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_ONLINE; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_ONLINE; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + case eGameSetting_InviteOnly: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_INVITEONLY)!=(ucVal&0x01)<<2) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_INVITEONLY; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_INVITEONLY; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + case eGameSetting_FriendsOfFriends: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_FRIENDSOFFRIENDS)!=(ucVal&0x01)<<3) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_FRIENDSOFFRIENDS; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_FRIENDSOFFRIENDS; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + case eGameSetting_DisplayUpdateMessage: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DISPLAYUPDATEMSG)!=(ucVal&0x03)<<4) + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_DISPLAYUPDATEMSG; + if(ucVal>0) + { + GameSettingsA[iPad]->uiBitmaskValues|=(ucVal&0x03)<<4; + } + + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + + case eGameSetting_BedrockFog: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_BEDROCKFOG)!=(ucVal&0x01)<<6) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_BEDROCKFOG; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_BEDROCKFOG; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + case eGameSetting_DisplayHUD: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DISPLAYHUD)!=(ucVal&0x01)<<7) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_DISPLAYHUD; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_DISPLAYHUD; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + case eGameSetting_DisplayHand: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DISPLAYHAND)!=(ucVal&0x01)<<8) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_DISPLAYHAND; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_DISPLAYHAND; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + + case eGameSetting_CustomSkinAnim: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_CUSTOMSKINANIM)!=(ucVal&0x01)<<9) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_CUSTOMSKINANIM; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_CUSTOMSKINANIM; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + + break; + // TU9 + case eGameSetting_DeathMessages: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DEATHMESSAGES)!=(ucVal&0x01)<<10) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_DEATHMESSAGES; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_DEATHMESSAGES; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_UISize: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_UISIZE)!=((ucVal&0x03)<<11)) + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_UISIZE; + if(ucVal!=0) + { + GameSettingsA[iPad]->uiBitmaskValues|=(ucVal&0x03)<<11; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_UISizeSplitscreen: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_UISIZE_SPLITSCREEN)!=((ucVal&0x03)<<13)) + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_UISIZE_SPLITSCREEN; + if(ucVal!=0) + { + GameSettingsA[iPad]->uiBitmaskValues|=(ucVal&0x03)<<13; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_AnimatedCharacter: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_ANIMATEDCHARACTER)!=(ucVal&0x01)<<15) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_ANIMATEDCHARACTER; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_ANIMATEDCHARACTER; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_PS3_EULA_Read: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_PS3EULAREAD)!=(ucVal&0x01)<<16) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_PS3EULAREAD; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_PS3EULAREAD; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + case eGameSetting_PSVita_NetworkModeAdhoc: + if((GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_PSVITANETWORKMODEADHOC)!=(ucVal&0x01)<<17) + { + if(ucVal==1) + { + GameSettingsA[iPad]->uiBitmaskValues|=GAMESETTING_PSVITANETWORKMODEADHOC; + } + else + { + GameSettingsA[iPad]->uiBitmaskValues&=~GAMESETTING_PSVITANETWORKMODEADHOC; + } + ActionGameSettings(iPad,eVal); + GameSettingsA[iPad]->bSettingsChanged=true; + } + break; + + } +} + +unsigned char CMinecraftApp::GetGameSettings(eGameSetting eVal) +{ + int iPad=ProfileManager.GetPrimaryPad(); + + return GetGameSettings(iPad,eVal); +} + +unsigned char CMinecraftApp::GetGameSettings(int iPad,eGameSetting eVal) +{ + switch(eVal) + { + case eGameSetting_MusicVolume: + return GameSettingsA[iPad]->ucMusicVolume; + break; + case eGameSetting_SoundFXVolume: + return GameSettingsA[iPad]->ucSoundFXVolume; + break; + case eGameSetting_Gamma: + return GameSettingsA[iPad]->ucGamma; + break; + case eGameSetting_Difficulty: + return GameSettingsA[iPad]->usBitmaskValues&0x0003; + break; + case eGameSetting_Sensitivity_InGame: + return GameSettingsA[iPad]->ucSensitivity; + break; + case eGameSetting_ViewBob: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0004)>>2); + break; + case eGameSetting_GamertagsVisible: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0008)>>3); + break; + case eGameSetting_ControlScheme: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0030)>>4); // 2 bits + break; + case eGameSetting_ControlInvertLook: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0040)>>6); + break; + case eGameSetting_ControlSouthPaw: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0080)>>7); + break; + case eGameSetting_SplitScreenVertical: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0100)>>8); + break; + // 4J-PB - Added for Interim TU for 1.6.6 + case eGameSetting_Sensitivity_InMenu: + return GameSettingsA[iPad]->ucMenuSensitivity; + break; + + case eGameSetting_DisplaySplitscreenGamertags: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0200)>>9); + break; + + case eGameSetting_Hints: + return ((GameSettingsA[iPad]->usBitmaskValues&0x0400)>>10); + break; + case eGameSetting_Autosave: + { + unsigned char ucVal=(GameSettingsA[iPad]->usBitmaskValues&0x7800)>>11; + return ucVal; + } + break; + case eGameSetting_Tooltips: + return ((GameSettingsA[iPad]->usBitmaskValues&0x8000)>>15); + break; + + case eGameSetting_InterfaceOpacity: + return GameSettingsA[iPad]->ucInterfaceOpacity; + break; + + case eGameSetting_Clouds: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_CLOUDS); + break; + case eGameSetting_Online: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_ONLINE)>>1; + break; + case eGameSetting_InviteOnly: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_INVITEONLY)>>2; + break; + case eGameSetting_FriendsOfFriends: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_FRIENDSOFFRIENDS)>>3; + break; + case eGameSetting_DisplayUpdateMessage: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DISPLAYUPDATEMSG)>>4; + break; + case eGameSetting_BedrockFog: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_BEDROCKFOG)>>6; + break; + case eGameSetting_DisplayHUD: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DISPLAYHUD)>>7; + break; + case eGameSetting_DisplayHand: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DISPLAYHAND)>>8; + break; + case eGameSetting_CustomSkinAnim: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_CUSTOMSKINANIM)>>9; + break; + // TU9 + case eGameSetting_DeathMessages: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_DEATHMESSAGES)>>10; + break; + case eGameSetting_UISize: + { + unsigned char ucVal=(GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_UISIZE)>>11; + return ucVal; + } + break; + case eGameSetting_UISizeSplitscreen: + { + unsigned char ucVal=(GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_UISIZE_SPLITSCREEN)>>13; + return ucVal; + } + break; + case eGameSetting_AnimatedCharacter: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_ANIMATEDCHARACTER)>>15; + + case eGameSetting_PS3_EULA_Read: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_PS3EULAREAD)>>16; + + case eGameSetting_PSVita_NetworkModeAdhoc: + return (GameSettingsA[iPad]->uiBitmaskValues&GAMESETTING_PSVITANETWORKMODEADHOC)>>17; + + } + return 0; +} + +void CMinecraftApp::CheckGameSettingsChanged(bool bOverride5MinuteTimer, int iPad) +{ + // If the settings have changed, write them to the profile + + if(iPad==XUSER_INDEX_ANY) + { + for(int i=0;ibSettingsChanged) + { +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__ ) + StorageManager.WriteToProfile(i,true, bOverride5MinuteTimer); +#else + ProfileManager.WriteToProfile(i,true, bOverride5MinuteTimer); +#endif + GameSettingsA[i]->bSettingsChanged=false; + } + } + } + else + { + if(GameSettingsA[iPad]->bSettingsChanged) + { +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + StorageManager.WriteToProfile(iPad,true, bOverride5MinuteTimer); +#else + ProfileManager.WriteToProfile(iPad,true, bOverride5MinuteTimer); +#endif + GameSettingsA[iPad]->bSettingsChanged=false; + } + } +} + +void CMinecraftApp::ClearGameSettingsChangedFlag(int iPad) +{ + GameSettingsA[iPad]->bSettingsChanged=false; +} + +/////////////////////////// +// +// Remove the debug settings in the content package build +// +//////////////////////////// +#ifndef _DEBUG_MENUS_ENABLED +unsigned int CMinecraftApp::GetGameSettingsDebugMask(int iPad,bool bOverridePlayer) //bOverridePlayer is to force the send for the server to get the read options +{ + return 0; +} + +void CMinecraftApp::SetGameSettingsDebugMask(int iPad, unsigned int uiVal) +{ +} + +void CMinecraftApp::ActionDebugMask(int iPad,bool bSetAllClear) +{ +} + +#else + +unsigned int CMinecraftApp::GetGameSettingsDebugMask(int iPad,bool bOverridePlayer) //bOverridePlayer is to force the send for the server to get the read options +{ + if(iPad==-1) + { + iPad=ProfileManager.GetPrimaryPad(); + } + if(iPad < 0) iPad = 0; + + shared_ptr player = Minecraft::GetInstance()->localplayers[iPad]; + + if(bOverridePlayer || player==NULL) + { + return GameSettingsA[iPad]->uiDebugBitmask; + } + else + { + return player->GetDebugOptions(); + } +} + + +void CMinecraftApp::SetGameSettingsDebugMask(int iPad, unsigned int uiVal) +{ +#ifndef _CONTENT_PACKAGE + GameSettingsA[iPad]->bSettingsChanged=true; + GameSettingsA[iPad]->uiDebugBitmask=uiVal; + + // update the value so the network server can use it + shared_ptr player = Minecraft::GetInstance()->localplayers[iPad]; + + if(player) + { + Minecraft::GetInstance()->localgameModes[iPad]->handleDebugOptions(uiVal,player); + } +#endif +} + +void CMinecraftApp::ActionDebugMask(int iPad,bool bSetAllClear) +{ + unsigned int ulBitmask=app.GetGameSettingsDebugMask(iPad); + + if(bSetAllClear) ulBitmask=0L; + + + + // these settings should only be actioned for the primary player + if(ProfileManager.GetPrimaryPad()!=iPad) return; + + for(int i=0;iiPad, actionInfo->action); +} + + +void CMinecraftApp::HandleXuiActions(void) +{ + eXuiAction eAction; + eTMSAction eTMS; + LPVOID param; + Minecraft *pMinecraft=Minecraft::GetInstance(); + shared_ptr player; + + // are there any global actions to deal with? + eAction = app.GetGlobalXuiAction(); + if(eAction!=eAppAction_Idle) + { + switch(eAction) + { + case eAppAction_DisplayLavaMessage: + // Display a warning about placing lava in the spawn area + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_CANT_PLACE_NEAR_SPAWN_TITLE, IDS_CANT_PLACE_NEAR_SPAWN_TEXT, uiIDA,1,XUSER_INDEX_ANY,NULL,NULL, app.GetStringTable()); + if(result != C4JStorage::EMessage_Busy) SetGlobalXuiAction(eAppAction_Idle); + + } + break; + default: + break; + } + } + + // are there any app actions to deal with? + for(int i=0;iIsTitleAllowedToPostImages() && CSocialManager::Instance()->AreAllUsersAllowedToPostImages() ) + { + // disable character name tags for the shot + //m_bwasHidingGui = pMinecraft->options->hideGui; // 4J Stu - Removed 1.8.2 bug fix (TU6) as don't need this + pMinecraft->options->hideGui = true; + + SetAction(i,eAppAction_SocialPostScreenshot); + } + else + { + SetAction(i,eAppAction_Idle); + } + } + else + { + SetAction(i,eAppAction_Idle); + } + break; + case eAppAction_SocialPostScreenshot: + { + SetAction(i,eAppAction_Idle); + bool bKeepHiding = false; + for(int j=0; j < XUSER_MAX_COUNT;++j) + { + if(app.GetXuiAction(j) == eAppAction_SocialPostScreenshot) + { + bKeepHiding = true; + break; + } + } + pMinecraft->options->hideGui=bKeepHiding; + + // Facebook Share + + if(app.GetLocalPlayerCount()>1) + { + ui.NavigateToScene(i,eUIScene_SocialPost); + } + else + { + ui.NavigateToScene(i,eUIScene_SocialPost); + } + } + break; + case eAppAction_SaveGame: + SetAction(i,eAppAction_Idle); + if(!GetChangingSessionType()) + { + // If this is the trial game, do an upsell + if(ProfileManager.IsFullVersion()) + { + + // flag the render to capture the screenshot for the save + SetAction(i,eAppAction_SaveGameCapturedThumbnail); + } + else + { + // ask the player if they would like to upgrade, or they'll lose the level + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_TOSAVE_TEXT, uiIDA, 2,i,&CMinecraftApp::UnlockFullSaveReturned,this,app.GetStringTable()); + } + } + + break; + case eAppAction_AutosaveSaveGame: + { + // Need to run a check to see if the save exists in order to stop the dialog asking if we want to overwrite it coming up on an autosave + bool bSaveExists; + StorageManager.DoesSaveExist(&bSaveExists); + + SetAction(i,eAppAction_Idle); + if(!GetChangingSessionType()) + { + + // flag the render to capture the screenshot for the save + SetAction(i,eAppAction_AutosaveSaveGameCapturedThumbnail); + } + } + + break; + + case eAppAction_SaveGameCapturedThumbnail: + // reset the autosave timer + app.SetAutosaveTimerTime(); + SetAction(i,eAppAction_Idle); + // Check that there is a name for the save - if we're saving from the tutorial and this is the first save from the tutorial, we'll not have a name + /*if(StorageManager.GetSaveName()==NULL) + { + app.NavigateToScene(i,eUIScene_SaveWorld); + } + else*/ + { + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // Hide the other players scenes + ui.ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), false); + + //INT saveOrCheckpointId = 0; + //bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); + //SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &UIScene_PauseMenu::SaveWorldThreadProc; + loadingParams->lpParam = (LPVOID)false; + + // 4J-JEV - PS4: Fix for #5708 - [ONLINE] - If the user pulls their network cable out while saving the title will hang. + loadingParams->waitForThreadToDelete = true; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_NavigateBackToScene; + completionData->iPad = ProfileManager.GetPrimaryPad(); + + if( ui.IsSceneInStack( ProfileManager.GetPrimaryPad(), eUIScene_EndPoem ) ) + { + completionData->scene = eUIScene_EndPoem; + } + else + { + completionData->scene = eUIScene_PauseMenu; + } + + loadingParams->completionData = completionData; + + // 4J Stu - Xbox only +#ifdef _XBOX + // Temporarily make this scene fullscreen + CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen ); +#endif + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams , eUILayer_Fullscreen, eUIGroup_Fullscreen); + + } + break; + case eAppAction_AutosaveSaveGameCapturedThumbnail: + + { + app.SetAutosaveTimerTime(); + SetAction(i,eAppAction_Idle); + +#if defined(_XBOX_ONE) || defined(__ORBIS__) + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_AutoSaveGame); + + if(app.GetGameHostOption(eGameHostOption_DisableSaving)) StorageManager.SetSaveDisabled(true); +#else + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + //app.CloseAllPlayersXuiScenes(); + // Hide the other players scenes + ui.ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), false); + + // This just allows it to be shown + if(pMinecraft->localgameModes[ProfileManager.GetPrimaryPad()] != NULL) pMinecraft->localgameModes[ProfileManager.GetPrimaryPad()]->getTutorial()->showTutorialPopup(false); + + //INT saveOrCheckpointId = 0; + //bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); + //SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId); + + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &UIScene_PauseMenu::SaveWorldThreadProc; + + loadingParams->lpParam = (LPVOID)true; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_AutosaveNavigateBack; + completionData->iPad = ProfileManager.GetPrimaryPad(); + //completionData->bAutosaveWasMenuDisplayed=ui.GetMenuDisplayed(ProfileManager.GetPrimaryPad()); + loadingParams->completionData = completionData; + + // 4J Stu - Xbox only +#ifdef _XBOX + // Temporarily make this scene fullscreen + CXuiSceneBase::SetPlayerBaseScenePosition( ProfileManager.GetPrimaryPad(), CXuiSceneBase::e_BaseScene_Fullscreen ); +#endif + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams , eUILayer_Fullscreen, eUIGroup_Fullscreen); +#endif + } + break; + case eAppAction_ExitPlayer: + // a secondary player has chosen to quit + { + int iPlayerC=g_NetworkManager.GetPlayerCount(); + + // Since the player is exiting, let's flush any profile writes for them, and hope we're not breaking TCR 136... +#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + StorageManager.ForceQueuedProfileWrites(i); + LeaderboardManager::Instance()->OpenSession(); + for (int j = 0; j < XUSER_MAX_COUNT; j++) + { + if( ProfileManager.IsSignedIn(j) ) + { + app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0); + Minecraft::GetInstance()->forceStatsSave(j); + } + } + LeaderboardManager::Instance()->CloseSession(); +#else + ProfileManager.ForceQueuedProfileWrites(i); +#endif + + // not required - it's done within the removeLocalPlayerIdx + // if(pMinecraft->level->isClientSide) + // { + // // we need to remove the qnetplayer, or this player won't be able to get back into the game until qnet times out and removes them + // g_NetworkManager.NotifyPlayerLeaving(g_NetworkManager.GetLocalPlayerByUserIndex(i)); + // } + + // if there are any tips showing, we need to close them + + pMinecraft->gui->clearMessages(i); + + // Make sure we've not got this player selected as current - this shouldn't be the case anyway + pMinecraft->setLocalPlayerIdx(ProfileManager.GetPrimaryPad()); + pMinecraft->removeLocalPlayerIdx(i); + +#ifdef _XBOX + // tell the xui scenes a splitscreen player left - has to come after removeLocalPlayerIdx which calls updatePlayerViewportAssignments + XUIMessage xuiMsg; + CustomMessage_Splitscreenplayer_Struct myMsgData; + CustomMessage_Splitscreenplayer( &xuiMsg, &myMsgData, false); + + // send the message + for(int idx=0;idxlocalplayers[idx]!=NULL)) + { + XuiBroadcastMessage( CXuiSceneBase::GetPlayerBaseScene(idx), &xuiMsg ); + } + } +#endif + +#ifndef _XBOX + // Wipe out the tooltips + ui.SetTooltips(i, -1); +#endif + + // Change the presence info + // Are we offline or online, and how many players are there + if(iPlayerC>2) // one player is about to leave here - they'll be set to idle in the qnet manager player leave + { + for(int iPlayer=0;iPlayerlocalplayers[iPlayer]) + { + if(g_NetworkManager.IsLocalGame()) + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false); + } + else + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYER,false); + } + } + } + } + else + { + for(int iPlayer=0;iPlayerlocalplayers[iPlayer]) + { + if(g_NetworkManager.IsLocalGame()) + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false); + } + else + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYER_1P,false); + } + } + } + } + +#ifdef _DURANGO + ProfileManager.RemoveGamepadFromGame(i); +#endif + + SetAction(i,eAppAction_Idle); + } + break; + case eAppAction_ExitPlayerPreLogin: + { + int iPlayerC=g_NetworkManager.GetPlayerCount(); + // Since the player is exiting, let's flush any profile writes for them, and hope we're not breaking TCR 136... +#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + StorageManager.ForceQueuedProfileWrites(i); +#else + ProfileManager.ForceQueuedProfileWrites(i); +#endif + // if there are any tips showing, we need to close them + + pMinecraft->gui->clearMessages(i); + + // Make sure we've not got this player selected as current - this shouldn't be the case anyway + pMinecraft->setLocalPlayerIdx(ProfileManager.GetPrimaryPad()); + pMinecraft->removeLocalPlayerIdx(i); + +#ifdef _XBOX + // tell the xui scenes a splitscreen player left - has to come after removeLocalPlayerIdx which calls updatePlayerViewportAssignments + XUIMessage xuiMsg; + CustomMessage_Splitscreenplayer_Struct myMsgData; + CustomMessage_Splitscreenplayer( &xuiMsg, &myMsgData, false); + + // send the message + for(int idx=0;idxlocalplayers[idx]!=NULL)) + { + XuiBroadcastMessage( CXuiSceneBase::GetPlayerBaseScene(idx), &xuiMsg ); + } + } +#endif + +#ifndef _XBOX + // Wipe out the tooltips + ui.SetTooltips(i, -1); +#endif + + // Change the presence info + // Are we offline or online, and how many players are there + if(iPlayerC>2) // one player is about to leave here - they'll be set to idle in the qnet manager player leave + { + for(int iPlayer=0;iPlayerlocalplayers[iPlayer]) + { + if(g_NetworkManager.IsLocalGame()) + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false); + } + else + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYER,false); + } + } + } + } + else + { + for(int iPlayer=0;iPlayerlocalplayers[iPlayer]) + { + if(g_NetworkManager.IsLocalGame()) + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false); + } + else + { + ProfileManager.SetCurrentGameActivity(iPlayer,CONTEXT_PRESENCE_MULTIPLAYER_1P,false); + } + } + } + } + SetAction(i,eAppAction_Idle); + } + break; + +#ifdef __ORBIS__ + case eAppAction_OptionsSaveNoSpace: + { + SetAction(i,eAppAction_Idle); + + SceSaveDataDialogParam param; + SceSaveDataDialogSystemMessageParam sysParam; + SceSaveDataDialogItems items; + SceSaveDataDirName dirName; + + sceSaveDataDialogParamInitialize(¶m); + param.mode = SCE_SAVE_DATA_DIALOG_MODE_SYSTEM_MSG; + param.dispType = SCE_SAVE_DATA_DIALOG_TYPE_SAVE; + memset(&sysParam,0,sizeof(sysParam)); + param.sysMsgParam = &sysParam; + param.sysMsgParam->sysMsgType = SCE_SAVE_DATA_DIALOG_SYSMSG_TYPE_NOSPACE_CONTINUABLE; + param.sysMsgParam->value = app.GetOptionsBlocksRequired(i); + memset(&items, 0, sizeof(items)); + param.items = &items; + param.items->userId = ProfileManager.getUserID(i); + + int ret = sceSaveDataDialogInitialize(); + ret = sceSaveDataDialogOpen(¶m); + + app.SetOptionsSaveDataDialogRunning(true);//m_bOptionsSaveDataDialogRunning = true; + //pClass->m_eSaveIncompleteType = saveIncompleteType; + + //StorageManager.SetSaveDisabled(true); + //pClass->EnterSaveNotificationSection(); + + } + break; +#endif + + case eAppAction_ExitWorld: + + SetAction(i,eAppAction_Idle); + + // If we're already leaving don't exit + if (g_NetworkManager.IsLeavingGame()) + { + break; + } + + pMinecraft->gui->clearMessages(); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // reset the flag stopping new dlc message being shown if you've seen the message before + DisplayNewDLCTipAgain(); + + // clear the autosave timer that might be on screen + ui.ShowAutosaveCountdownTimer(false); + + // Hide the selected item text + ui.HideAllGameUIElements(); + + // Since the player forced the exit, let's flush any profile writes, and hope we're not breaking TCR 136... +#if (defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + StorageManager.ForceQueuedProfileWrites(); + LeaderboardManager::Instance()->OpenSession(); + for (int j = 0; j < XUSER_MAX_COUNT; j++) + { + if( ProfileManager.IsSignedIn(j) ) + { + app.DebugPrintf("Stats save for an offline game for the player at index %d\n", 0); + Minecraft::GetInstance()->forceStatsSave(j); + } + } + LeaderboardManager::Instance()->CloseSession(); +#elif (defined _XBOX) + ProfileManager.ForceQueuedProfileWrites(); +#endif + + // 4J-PB - cancel any possible string verifications queued with LIVE + //InputManager.CancelAllVerifyInProgress(); + + if(ProfileManager.IsFullVersion()) + { + + // In a split screen, only the primary player actually quits the game, others just remove their players + if( i != ProfileManager.GetPrimaryPad() ) + { + // Make sure we've not got this player selected as current - this shouldn't be the case anyway + pMinecraft->setLocalPlayerIdx(ProfileManager.GetPrimaryPad()); + pMinecraft->removeLocalPlayerIdx(i); + +#ifdef _DURANGO + ProfileManager.RemoveGamepadFromGame(i); +#endif + SetAction(i,eAppAction_Idle); + return; + } + // flag to capture the save thumbnail + SetAction(i,eAppAction_ExitWorldCapturedThumbnail, param); + } + else + { + // ask the player if they would like to upgrade, or they'll lose the level + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_TOSAVE_TEXT, uiIDA, 2, i,&CMinecraftApp::UnlockFullExitReturned,this,app.GetStringTable()); + } + + // Change the presence info + // Are we offline or online, and how many players are there + + if(g_NetworkManager.GetPlayerCount()>1) + { + for(int j=0;jlocalplayers[j]) + { + if(g_NetworkManager.IsLocalGame()) + { + app.SetRichPresenceContext(j,CONTEXT_GAME_STATE_BLANK); + ProfileManager.SetCurrentGameActivity(j,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false); + } + else + { + app.SetRichPresenceContext(j,CONTEXT_GAME_STATE_BLANK); + ProfileManager.SetCurrentGameActivity(j,CONTEXT_PRESENCE_MULTIPLAYER,false); + } + TelemetryManager->RecordLevelExit(j, eSen_LevelExitStatus_Exited); + } + } + } + else + { + app.SetRichPresenceContext(i,CONTEXT_GAME_STATE_BLANK); + if(g_NetworkManager.IsLocalGame()) + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false); + } + else + { + ProfileManager.SetCurrentGameActivity(i,CONTEXT_PRESENCE_MULTIPLAYER_1P,false); + } + TelemetryManager->RecordLevelExit(i, eSen_LevelExitStatus_Exited); + } + break; + case eAppAction_ExitWorldCapturedThumbnail: + { + SetAction(i,eAppAction_Idle); + // Stop app running + SetGameStarted(false); + SetChangingSessionType(true); // Added to stop handling ethernet disconnects + + ui.CloseAllPlayersScenes(); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // 4J Stu - Fix for #12368 - Crash: Game crashes when saving then exiting and selecting to save + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { +#ifdef _XBOX + app.TutorialSceneNavigateBack(idx,true); +#endif + + // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title crashed after exiting the tutorial + // It doesn't matter if they were in the tutorial already + pMinecraft->playerLeftTutorial( idx ); + } + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &UIScene_PauseMenu::ExitWorldThreadProc; + loadingParams->lpParam = param; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + // If param is non-null then this is a forced exit by the server, so make sure the player knows why + // 4J Stu - Changed - Don't use the FullScreenProgressScreen for action, use a dialog instead + completionData->bRequiresUserAction = FALSE;//(param != NULL) ? TRUE : FALSE; + completionData->bShowTips = (param != NULL) ? FALSE : TRUE; + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_NavigateToHomeMenu; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + break; + case eAppAction_ExitWorldTrial: + { + SetAction(i,eAppAction_Idle); + + pMinecraft->gui->clearMessages(); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // Stop app running + SetGameStarted(false); + + ui.CloseAllPlayersScenes(); + + // 4J Stu - Fix for #12368 - Crash: Game crashes when saving then exiting and selecting to save + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { +#ifdef _XBOX + app.TutorialSceneNavigateBack(idx,true); +#endif + + // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title crashed after exiting the tutorial + // It doesn't matter if they were in the tutorial already + pMinecraft->playerLeftTutorial( idx ); + } + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &UIScene_PauseMenu::ExitWorldThreadProc; + loadingParams->lpParam = param; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_NavigateToHomeMenu; + completionData->iPad = DEFAULT_XUI_MENU_USER; + loadingParams->completionData = completionData; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + + break; + case eAppAction_ExitTrial: + //XLaunchNewImage(XLAUNCH_KEYWORD_DASH_ARCADE, 0); + ExitGame(); + break; + + case eAppAction_Respawn: + { + ConnectionProgressParams *param = new ConnectionProgressParams(); + param->iPad = i; + param->stringId = IDS_PROGRESS_RESPAWNING; + param->showTooltips = false; + param->setFailTimer = false; + ui.NavigateToScene(i,eUIScene_ConnectingProgress, param); + + // Need to reset this incase the player has already died and respawned + pMinecraft->localplayers[i]->SetPlayerRespawned(false); + + SetAction(i,eAppAction_WaitForRespawnComplete); + if( app.GetLocalPlayerCount()>1 ) + { + // In split screen mode, we don't want to do any async loading or flushing of the cache, just a simple respawn + pMinecraft->localplayers[i]->respawn(); + + // If the respawn requires a dimension change then the action will have changed + //if(app.GetXuiAction(i) == eAppAction_Respawn) + //{ + // SetAction(i,eAppAction_Idle); + // CloseXuiScenes(i); + //} + } + else + { + //SetAction(i,eAppAction_WaitForRespawnComplete); + + //LoadingInputParams *loadingParams = new LoadingInputParams(); + //loadingParams->func = &CScene_Death::RespawnThreadProc; + //loadingParams->lpParam = (LPVOID)i; + + // Disable game & update thread whilst we do any of this + //app.SetGameStarted(false); + pMinecraft->gameRenderer->DisableUpdateThread(); + + // 4J Stu - We don't need this on a thread in multiplayer as respawning is asynchronous. + pMinecraft->localplayers[i]->respawn(); + + //app.SetGameStarted(true); + pMinecraft->gameRenderer->EnableUpdateThread(); + + //UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + //completionData->bShowBackground=TRUE; + //completionData->bShowLogo=TRUE; + //completionData->type = e_ProgressCompletion_CloseUIScenes; + //completionData->iPad = i; + //loadingParams->completionData = completionData; + + //app.NavigateToScene(i,eUIScene_FullscreenProgress, loadingParams, true); + } + } + break; + case eAppAction_WaitForRespawnComplete: + player = pMinecraft->localplayers[i]; + if(player != NULL && player->GetPlayerRespawned()) + { + SetAction(i,eAppAction_Idle); + + if(ui.IsSceneInStack(i, eUIScene_EndPoem)) + { + ui.NavigateBack(i,false,eUIScene_EndPoem); + } + else + { + ui.CloseUIScenes(i); + } + + // clear the progress messages + +// pMinecraft->progressRenderer->progressStart(-1); +// pMinecraft->progressRenderer->progressStage(-1); + } + else if(!g_NetworkManager.IsInGameplay()) + { + SetAction(i,eAppAction_Idle); + } + break; + case eAppAction_WaitForDimensionChangeComplete: + player = pMinecraft->localplayers[i]; + if(player != NULL && player->connection && player->connection->isStarted()) + { + SetAction(i,eAppAction_Idle); + ui.CloseUIScenes(i); + } + else if(!g_NetworkManager.IsInGameplay()) + { + SetAction(i,eAppAction_Idle); + } + break; + case eAppAction_PrimaryPlayerSignedOut: + { + //SetAction(i,eAppAction_Idle); + + // clear the autosavetimer that might be displayed + ui.ShowAutosaveCountdownTimer(false); + + // If the player signs out before the game started the server can be killed a bit earlier to stop + // the loading or saving of a new game continuing running while the UI/Guide is up + if(!app.GetGameStarted()) MinecraftServer::HaltServer(true); + + // inform the player they are being returned to the menus because they signed out + StorageManager.SetSaveDeviceSelected(i,false); + // need to clear the player stats - can't assume it'll be done in setlevel - we may not be in the game + StatsCounter* pStats = Minecraft::GetInstance()->stats[ i ]; + pStats->clear(); + + // 4J-PB - the libs will display the Returned to Title screen +// UINT uiIDA[1]; +// uiIDA[0]=IDS_CONFIRM_OK; +// +// ui.RequestMessageBox(IDS_RETURNEDTOMENU_TITLE, IDS_RETURNEDTOTITLESCREEN_TEXT, uiIDA, 1, i,&CMinecraftApp::PrimaryPlayerSignedOutReturned,this,app.GetStringTable()); + if( g_NetworkManager.IsInSession() ) + { + app.SetAction(i,eAppAction_PrimaryPlayerSignedOutReturned); + } + else + { + app.SetAction(i,eAppAction_PrimaryPlayerSignedOutReturned_Menus); + MinecraftServer::resetFlags(); + } + } + break; + case eAppAction_EthernetDisconnected: + { + app.DebugPrintf("Handling eAppAction_EthernetDisconnected\n"); + SetAction(i,eAppAction_Idle); + + // 4J Stu - Fix for #12530 -TCR 001 BAS Game Stability: Title will crash if the player disconnects while starting a new world and then opts to play the tutorial once they have been returned to the Main Menu. + if(!g_NetworkManager.IsLeavingGame()) + { + app.DebugPrintf("Handling eAppAction_EthernetDisconnected - Not leaving game\n"); + // 4J-PB - not the same as a signout. We should only leave the game if this machine is not the host. We shouldn't get rid of the save device either. + if( g_NetworkManager.IsHost() ) + { + app.DebugPrintf("Handling eAppAction_EthernetDisconnected - Is Host\n"); + // If it's already a local game, then an ethernet disconnect should have no effect + if( !g_NetworkManager.IsLocalGame() && g_NetworkManager.IsInGameplay() ) + { + // Change the session to an offline session + SetAction(i,eAppAction_ChangeSessionType); + } + else if(!g_NetworkManager.IsLocalGame() && !g_NetworkManager.IsInGameplay() ) + { + // There are two cases here, either: + // 1. We're early enough in the create/load game that we can do a really minimal shutdown or + // 2. We're far enough in (game has started but the actual game started flag hasn't been set) that we should just wait until we're in the game and switch to offline mode + + // If there's a non-null level then, for our purposes, the game has started + bool gameStarted = false; + for(int i = 0; i < pMinecraft->levels.length; i++) + { + if (pMinecraft->levels.data[i] != nullptr) + { + gameStarted = true; + break; + } + } + + if (!gameStarted) + { + // 1. Exit + MinecraftServer::HaltServer(); + + // Fix for #12530 - TCR 001 BAS Game Stability: Title will crash if the player disconnects while starting a new world and then opts to play the tutorial once they have been returned to the Main Menu. + // 4J Stu - Leave the session + g_NetworkManager.LeaveGame(FALSE); + + // need to clear the player stats - can't assume it'll be done in setlevel - we may not be in the game + StatsCounter* pStats = Minecraft::GetInstance()->stats[ i ]; + pStats->clear(); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + ui.RequestMessageBox(g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST), g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE), uiIDA, 1, i,&CMinecraftApp::EthernetDisconnectReturned,this, app.GetStringTable()); + } + else + { + // 2. Switch to offline + SetAction(i,eAppAction_ChangeSessionType); + } + } + } + else + { + app.DebugPrintf("Handling eAppAction_EthernetDisconnected - Not host\n"); + // need to clear the player stats - can't assume it'll be done in setlevel - we may not be in the game + StatsCounter* pStats = Minecraft::GetInstance()->stats[ i ]; + pStats->clear(); + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + ui.RequestMessageBox(g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST), g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE), uiIDA, 1, i,&CMinecraftApp::EthernetDisconnectReturned,this, app.GetStringTable()); + } + } + } + break; + // We currently handle both these returns the same way. + case eAppAction_EthernetDisconnectedReturned: + case eAppAction_PrimaryPlayerSignedOutReturned: + { + SetAction(i,eAppAction_Idle); + + pMinecraft->gui->clearMessages(); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // set the state back to pre-game + ProfileManager.ResetProfileProcessState(); + + + if( g_NetworkManager.IsLeavingGame() ) + { + // 4J Stu - If we are already leaving the game, then we just need to signal that the player signed out to stop saves + pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME ); + pMinecraft->progressRenderer->progressStage(-1); + // This has no effect on client machines + MinecraftServer::HaltServer(true); + } + else + { + // Stop app running + SetGameStarted(false); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + ui.CloseAllPlayersScenes(); + + // 4J Stu - Fix for #12368 - Crash: Game crashes when saving then exiting and selecting to save + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { +#ifdef _XBOX + app.TutorialSceneNavigateBack(idx,true); +#endif + + // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title crashed after exiting the tutorial + // It doesn't matter if they were in the tutorial already + pMinecraft->playerLeftTutorial( idx ); + } + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CMinecraftApp::SignoutExitWorldThreadProc; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->iPad=DEFAULT_XUI_MENU_USER; + completionData->type = e_ProgressCompletion_NavigateToHomeMenu; + loadingParams->completionData = completionData; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + } + break; + case eAppAction_PrimaryPlayerSignedOutReturned_Menus: + SetAction(i,eAppAction_Idle); + // set the state back to pre-game + ProfileManager.ResetProfileProcessState(); + // clear the save device + StorageManager.SetSaveDeviceSelected(i,false); + + ui.UpdatePlayerBasePositions(); + // there are multiple layers in the help menu, so a navigate back isn't enough + ui.NavigateToHomeMenu(); + + break; + case eAppAction_EthernetDisconnectedReturned_Menus: + SetAction(i,eAppAction_Idle); + // set the state back to pre-game + ProfileManager.ResetProfileProcessState(); + + ui.UpdatePlayerBasePositions(); + + // there are multiple layers in the help menu, so a navigate back isn't enough + ui.NavigateToHomeMenu(); + + break; + + case eAppAction_TrialOver: + { + SetAction(i,eAppAction_Idle); + UINT uiIDA[2]; + uiIDA[0]=IDS_UNLOCK_TITLE; + uiIDA[1]=IDS_EXIT_GAME; + + ui.RequestMessageBox(IDS_TRIALOVER_TITLE, IDS_TRIALOVER_TEXT, uiIDA, 2, i,&CMinecraftApp::TrialOverReturned,this,app.GetStringTable()); + } + break; + + // INVITES + case eAppAction_DashboardTrialJoinFromInvite: + { + TelemetryManager->RecordUpsellPresented(i, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID); + + SetAction(i,eAppAction_Idle); + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_ACCEPT_INVITE, uiIDA, 2, i,&CMinecraftApp::UnlockFullInviteReturned,this,app.GetStringTable()); + } + break; + case eAppAction_ExitAndJoinFromInvite: + { + UINT uiIDA[3]; + + SetAction(i,eAppAction_Idle); + // Check the player really wants to do this + +#if defined(_XBOX_ONE) || defined(__ORBIS__) + // Show save option is saves ARE disabled + if(ProfileManager.IsFullVersion() && StorageManager.GetSaveDisabled() && i==ProfileManager.GetPrimaryPad() && g_NetworkManager.IsHost() && GetGameStarted() ) + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_EXIT_GAME_SAVE; + uiIDA[2]=IDS_EXIT_GAME_NO_SAVE; + + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 3, i,&CMinecraftApp::ExitAndJoinFromInviteSaveDialogReturned,this, app.GetStringTable(), 0, 0, false); + } + else +#else + if(ProfileManager.IsFullVersion() && !StorageManager.GetSaveDisabled() && i==ProfileManager.GetPrimaryPad() && g_NetworkManager.IsHost() && GetGameStarted() ) + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_EXIT_GAME_SAVE; + uiIDA[2]=IDS_EXIT_GAME_NO_SAVE; + + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 3, i,&CMinecraftApp::ExitAndJoinFromInviteSaveDialogReturned,this, app.GetStringTable(), 0, 0, false); + } + else +#endif + { + if(!ProfileManager.IsFullVersion()) + { + TelemetryManager->RecordUpsellPresented(i, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID); + + // upsell + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + ui.RequestMessageBox(IDS_UNLOCK_TITLE, IDS_UNLOCK_ACCEPT_INVITE, uiIDA, 2, i,&CMinecraftApp::UnlockFullInviteReturned,this,app.GetStringTable()); + } + else + { + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_LEAVE_VIA_INVITE, uiIDA, 2,i,&CMinecraftApp::ExitAndJoinFromInvite,this,app.GetStringTable(), 0, 0, false); + } + } + } + break; + case eAppAction_ExitAndJoinFromInviteConfirmed: + { + SetAction(i,eAppAction_Idle); + + pMinecraft->gui->clearMessages(); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + // Stop app running + SetGameStarted(false); + + ui.CloseAllPlayersScenes(); + + // 4J Stu - Fix for #12368 - Crash: Game crashes when saving then exiting and selecting to save + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { +#ifdef _XBOX + app.TutorialSceneNavigateBack(idx,true); +#endif + + // 4J Stu - Fix for #13257 - CRASH: Gameplay: Title crashed after exiting the tutorial + // It doesn't matter if they were in the tutorial already + pMinecraft->playerLeftTutorial( idx ); + } + + // 4J-PB - may have been using a texture pack with audio , so clean up anything texture pack related here + + // unload any texture pack audio + // if there is audio in use, clear out the audio, and unmount the pack + TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=NULL; + + if(pTexPack->hasAudio()) + { + // get the dlc texture pack, and store it + pDLCTexPack=(DLCTexturePack *)pTexPack; + } + + // change to the default texture pack + pMinecraft->skins->selectTexturePackById(TexturePackRepository::DEFAULT_TEXTURE_PACK_ID); + + if(pTexPack->hasAudio()) + { + // need to stop the streaming audio - by playing streaming audio from the default texture pack now + // reset the streaming sounds back to the normal ones +#ifndef _XBOX + pMinecraft->soundEngine->SetStreamingSounds(eStream_Overworld_Calm1,eStream_Overworld_piano3, + eStream_Nether1,eStream_Nether4, + eStream_end_dragon,eStream_end_end, + eStream_CD_1); +#endif + pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1); + +#ifdef _XBOX + if(pDLCTexPack->m_pStreamedWaveBank!=NULL) + { + pDLCTexPack->m_pStreamedWaveBank->Destroy(); + } + if(pDLCTexPack->m_pSoundBank!=NULL) + { + pDLCTexPack->m_pSoundBank->Destroy(); + } +#endif +#ifdef _DURANGO + DWORD result = StorageManager.UnmountInstalledDLC(L"TPACK"); +#else + DWORD result = StorageManager.UnmountInstalledDLC("TPACK"); +#endif + app.DebugPrintf("Unmount result is %d\n",result); + } + +#ifdef _XBOX_ONE + // 4J Stu - It's possible that we can sign in/remove players between the mask initially being set and this point + m_InviteData.dwLocalUsersMask = 0; + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + if(index==i || pMinecraft->localplayers[index]!=NULL ) + { + m_InviteData.dwLocalUsersMask |= g_NetworkManager.GetLocalPlayerMask( index ); + } + } + } +#endif + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::ExitAndJoinFromInviteThreadProc; + loadingParams->lpParam = (LPVOID)&m_InviteData; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->iPad=DEFAULT_XUI_MENU_USER; + completionData->type = e_ProgressCompletion_NoAction; + loadingParams->completionData = completionData; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + + break; + case eAppAction_JoinFromInvite: + { + SetAction(i,eAppAction_Idle); + + // 4J Stu - Move this state block from CPlatformNetworkManager::ExitAndJoinFromInviteThreadProc, as g_NetworkManager.JoinGameFromInviteInfo ultimately can call NavigateToScene, + /// and we should only be calling that from the main thread + app.SetTutorialMode( false ); + + g_NetworkManager.SetLocalGame(false); + + JoinFromInviteData *inviteData = (JoinFromInviteData *)param; + // 4J-PB - clear any previous connection errors + Minecraft::GetInstance()->clearConnectionFailed(); + + app.DebugPrintf( "Changing Primary Pad on an invite accept - pad was %d, and is now %d\n", ProfileManager.GetPrimaryPad(), inviteData->dwUserIndex ); + ProfileManager.SetLockedProfile(inviteData->dwUserIndex); + ProfileManager.SetPrimaryPad(inviteData->dwUserIndex); + +#ifdef _XBOX_ONE + // 4J Stu - If a player is signed in (i.e. locked) but not in the mask, unlock them + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if( index != inviteData->dwUserIndex && ProfileManager.IsSignedIn(index) ) + { + if( (m_InviteData.dwLocalUsersMask & g_NetworkManager.GetLocalPlayerMask( index ) ) == 0 ) + { + ProfileManager.RemoveGamepadFromGame(index); + } + } + } +#endif + + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + + bool success = g_NetworkManager.JoinGameFromInviteInfo( + inviteData->dwUserIndex, // dwUserIndex + inviteData->dwLocalUsersMask, // dwUserMask + inviteData->pInviteInfo ); // pInviteInfo + + if( !success ) + { + app.DebugPrintf( "Failed joining game from invite\n" ); + //return hr; + + // 4J Stu - Copied this from XUI_FullScreenProgress to properly handle the fail case, as the thread will no longer be failing + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_LOST_SERVER, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + + ui.NavigateToHomeMenu(); + ui.UpdatePlayerBasePositions(); + } + } + break; + case eAppAction_ChangeSessionType: + { + // If we are not in gameplay yet, then wait until the server is setup before changing the session type + if( g_NetworkManager.IsInGameplay() ) + { + // This kicks off a thread that waits for the server to end, then closes the current session, starts a new one and joins the local players into it + + SetAction(i,eAppAction_Idle); + + if( !GetChangingSessionType() && !g_NetworkManager.IsLocalGame() ) + { + SetGameStarted(false); + SetChangingSessionType(true); + SetReallyChangingSessionType(true); + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + if( !ui.IsSceneInStack( ProfileManager.GetPrimaryPad(), eUIScene_EndPoem ) ) + { + ui.CloseAllPlayersScenes(); + } + ui.ShowOtherPlayersBaseScene(ProfileManager.GetPrimaryPad(), true); + + // Remove this line to fix: + // #49084 - TU5: Code: Gameplay: The title crashes every time client navigates to 'Play game' menu and loads/creates new game after a "Connection to Xbox LIVE was lost" message has appeared. + //app.NavigateToScene(0,eUIScene_Main); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::ChangeSessionTypeThreadProc; + loadingParams->lpParam = NULL; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); +#ifdef __PS3__ + completionData->bRequiresUserAction=FALSE; +#else + completionData->bRequiresUserAction=TRUE; +#endif + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->iPad=DEFAULT_XUI_MENU_USER; + if( ui.IsSceneInStack( ProfileManager.GetPrimaryPad(), eUIScene_EndPoem ) ) + { + completionData->type = e_ProgressCompletion_NavigateBackToScene; + completionData->scene = eUIScene_EndPoem; + } + else + { + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + } + loadingParams->completionData = completionData; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + } + else if( g_NetworkManager.IsLeavingGame() ) + { + // If we are leaving the game, then ignore the state change + SetAction(i,eAppAction_Idle); + } +#if 0 + // 4J-HG - Took this out since ChangeSessionType is only set in two places (both in EthernetDisconnected) and this case is handled there, plus this breaks + // this if statements original purpose (to allow us to wait for IsInGameplay before actioning switching to offline + + // QNet must do this kind of thing automatically by itself, but on PS3 at least, we need the disconnection to definitely end up with us out of the game one way or another, + // and the other two cases above don't catch the case where we are just starting the game and get a disconnection during the loading/creation + else + { + if( g_NetworkManager.IsInSession() ) + { + g_NetworkManager._LeaveGame(); + } + } +#endif + } + break; + case eAppAction_SetDefaultOptions: + SetAction(i,eAppAction_Idle); +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + SetDefaultOptions((C4JStorage::PROFILESETTINGS *)param,i); +#else + SetDefaultOptions((C_4JProfile::PROFILESETTINGS *)param,i); +#endif + + // if the profile data has been changed, then force a profile write + // It seems we're allowed to break the 5 minute rule if it's the result of a user action + CheckGameSettingsChanged(true,i); + + break; + + case eAppAction_RemoteServerSave: + { + // If the remote server save has already finished, don't complete the action + if (GetGameStarted()) + { + SetAction(ProfileManager.GetPrimaryPad(), eAppAction_Idle); + break; + } + + SetAction(i,eAppAction_WaitRemoteServerSaveComplete); + + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + ui.CloseUIScenes(i, true); + } + + // turn off the gamertags in splitscreen for the primary player, since they are about to be made fullscreen + ui.HideAllGameUIElements(); + + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CMinecraftApp::RemoteSaveThreadProc; + loadingParams->lpParam = NULL; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bRequiresUserAction=FALSE; + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->iPad=DEFAULT_XUI_MENU_USER; + if( ui.IsSceneInStack( ProfileManager.GetPrimaryPad(), eUIScene_EndPoem ) ) + { + completionData->type = e_ProgressCompletion_NavigateBackToScene; + completionData->scene = eUIScene_EndPoem; + } + else + { + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + } + loadingParams->completionData = completionData; + + loadingParams->cancelFunc = &CMinecraftApp::ExitGameFromRemoteSave; + loadingParams->cancelText = IDS_TOOLTIPS_EXIT; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } + break; + case eAppAction_WaitRemoteServerSaveComplete: + // Do nothing + break; + case eAppAction_FailedToJoinNoPrivileges: + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + if(result != C4JStorage::EMessage_Busy) SetAction(i,eAppAction_Idle); + } + break; + case eAppAction_ProfileReadError: + // Return player to the main menu - code largely copied from that for handling + // eAppAction_PrimaryPlayerSignedOut, although I don't think we should have got as + // far as needing to halt the server, or running the game, before returning to the menu + if(!app.GetGameStarted()) MinecraftServer::HaltServer(true); + + if( g_NetworkManager.IsInSession() ) + { + app.SetAction(i,eAppAction_PrimaryPlayerSignedOutReturned); + } + else + { + app.SetAction(i,eAppAction_PrimaryPlayerSignedOutReturned_Menus); + MinecraftServer::resetFlags(); + } + break; + + case eAppAction_BanLevel: + { + // It's possible that this state can get set after the game has been exited (e.g. by network disconnection) so we can't ban the level at that point + if(g_NetworkManager.IsInGameplay() && !g_NetworkManager.IsLeavingGame()) + { + TelemetryManager->RecordBanLevel(i); + +#if defined _XBOX + INetworkPlayer *pHost=g_NetworkManager.GetHostPlayer(); + // write the level to the banned level list, and exit the world + AddLevelToBannedLevelList(i,((NetworkPlayerXbox *)pHost)->GetUID(),GetUniqueMapName(),true); +#elif defined _XBOX_ONE + INetworkPlayer *pHost=g_NetworkManager.GetHostPlayer(); + AddLevelToBannedLevelList(i,pHost->GetUID(),GetUniqueMapName(),true); +#endif + // primary player would exit the world, secondary would exit the player + if(ProfileManager.GetPrimaryPad()==i) + { + SetAction(i,eAppAction_ExitWorld); + } + else + { + SetAction(i,eAppAction_ExitPlayer); + } + } + } + break; + case eAppAction_LevelInBanLevelList: + { + UINT uiIDA[2]; + uiIDA[0]=IDS_BUTTON_REMOVE_FROM_BAN_LIST; + uiIDA[1]=IDS_EXIT_GAME; + + // pass in the gamertag format string + WCHAR wchFormat[40]; + INetworkPlayer *player = g_NetworkManager.GetLocalPlayerByUserIndex(i); + + // If not the primary player, but the primary player has banned this level and decided not to unban + // then we may have left the game by now + if(player) + { + swprintf(wchFormat, 40, L"%ls\n\n%%ls",player->GetOnlineName()); + + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_BANNED_LEVEL_TITLE, IDS_PLAYER_BANNED_LEVEL, uiIDA,2,i,&CMinecraftApp::BannedLevelDialogReturned,this, app.GetStringTable(),wchFormat); + if(result != C4JStorage::EMessage_Busy) SetAction(i,eAppAction_Idle); + } + else + { + SetAction(i,eAppAction_Idle); + } + } + break; + case eAppAction_DebugText: + // launch the xui for text entry + { +#ifdef _XBOX + CScene_TextEntry::XuiTextInputParams *pDebugTextParams= new CScene_TextEntry::XuiTextInputParams; + pDebugTextParams->iPad=i; + pDebugTextParams->wch=(WCHAR)param; + + app.NavigateToScene(i,eUIScene_TextEntry,pDebugTextParams); +#endif + SetAction(i,eAppAction_Idle); + } + break; + + case eAppAction_ReloadTexturePack: + { + SetAction(i,eAppAction_Idle); + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->textures->reloadAll(); + pMinecraft->skins->updateUI(); + + if(!pMinecraft->skins->isUsingDefaultSkin()) + { + TexturePack *pTexturePack = pMinecraft->skins->getSelected(); + + DLCPack *pDLCPack=pTexturePack->getDLCPack(); + + bool purchased = false; + // do we have a license? + if(pDLCPack && pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + purchased = true; + } +#ifdef _XBOX + TelemetryManager->RecordTexturePackLoaded(i, pTexturePack->getId(), purchased?1:0); +#endif + } + + // 4J-PB - If the texture pack has audio, we need to switch to this + if(pMinecraft->skins->getSelected()->hasAudio()) + { + Minecraft::GetInstance()->soundEngine->playStreaming(L"", 0, 0, 0, 1, 1); + } + } + + break; + + case eAppAction_TexturePackRequired: + { +#ifdef _XBOX + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(app.GetRequiredTexturePackID(),&ullOfferID_Full); + + TelemetryManager->RecordUpsellPresented(ProfileManager.GetPrimaryPad(), eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); +#endif + UINT uiIDA[2]; + + uiIDA[0]=IDS_TEXTUREPACK_FULLVERSION; + uiIDA[1]=IDS_TEXTURE_PACK_TRIALVERSION; + + // Give the player a warning about the texture pack missing + ui.RequestMessageBox(IDS_DLC_TEXTUREPACK_NOT_PRESENT_TITLE, IDS_DLC_TEXTUREPACK_NOT_PRESENT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::TexturePackDialogReturned,this,app.GetStringTable()); + SetAction(i,eAppAction_Idle); + } + + break; + } + } + + // Any TMS actions? + + eTMS = app.GetTMSAction(i); + + if(eTMS!=eTMSAction_Idle) + { + switch(eTMS) + { + // TMS++ actions + case eTMSAction_TMSPP_RetrieveFiles_CreateLoad_SignInReturned: + case eTMSAction_TMSPP_RetrieveFiles_RunPlayGame: +#ifdef _XBOX + app.TMSPP_SetTitleGroupID(GROUP_ID); + SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList); +#elif defined _XBOX_ONE + SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,eTMSAction_TMSPP_UserFileList); +#else + SetTMSAction(i,eTMSAction_TMSPP_UserFileList); + #endif + break; + +#ifdef _XBOX + case eTMSAction_TMSPP_GlobalFileList: + SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,"\\",eTMSAction_TMSPP_UserFileList); + break; +#endif + case eTMSAction_TMSPP_UserFileList: + // retrieve the file list first +#if defined _XBOX + SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,"\\",eTMSAction_TMSPP_XUIDSFile); +#elif defined _XBOX_ONE + SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,eTMSAction_TMSPP_DLCFile); +#else + SetTMSAction(i,eTMSAction_TMSPP_XUIDSFile); +#endif + break; + case eTMSAction_TMSPP_XUIDSFile: +#ifdef _XBOX + SetTMSAction(i,eTMSAction_TMSPP_XUIDSFile_Waiting); + // pass in the next app action on the call or callback completing + app.TMSPP_ReadXuidsFile(i,eTMSAction_TMSPP_DLCFile); +#else + SetTMSAction(i,eTMSAction_TMSPP_DLCFile); +#endif + + break; + case eTMSAction_TMSPP_DLCFile: +#if defined _XBOX || defined _XBOX_ONE + SetTMSAction(i,eTMSAction_TMSPP_DLCFile_Waiting); + // pass in the next app action on the call or callback completing + app.TMSPP_ReadDLCFile(i,eTMSAction_TMSPP_BannedListFile); +#else + SetTMSAction(i,eTMSAction_TMSPP_BannedListFile); +#endif + break; + case eTMSAction_TMSPP_BannedListFile: + // If we have one in TMSPP, then we can assume we can ignore TMS +#if defined _XBOX + SetTMSAction(i,eTMSAction_TMSPP_BannedListFile_Waiting); + // pass in the next app action on the call or callback completing + if(app.TMSPP_ReadBannedList(i,eTMSAction_TMS_RetrieveFiles_Complete)==false) + { + // we don't have a banned list in TMSPP, so we should check TMS + app.ReadBannedList(i, eTMSAction_TMS_RetrieveFiles_Complete,true); + } +#elif defined _XBOX_ONE + SetTMSAction(i,eTMSAction_TMSPP_BannedListFile_Waiting); + // pass in the next app action on the call or callback completing + app.TMSPP_ReadBannedList(i,eTMSAction_TMS_RetrieveFiles_Complete); + +#else + SetTMSAction(i,eTMSAction_TMS_RetrieveFiles_Complete); +#endif + break; + + // SPECIAL CASE - where the user goes directly in to Help & Options from the main menu + case eTMSAction_TMSPP_RetrieveFiles_HelpAndOptions: + case eTMSAction_TMSPP_RetrieveFiles_DLCMain: + // retrieve the file list first +#if defined _XBOX + // pass in the next app action on the call or callback completing + SetTMSAction(i,eTMSAction_TMSPP_XUIDSFile_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,"\\",eTMSAction_TMSPP_DLCFileOnly); +#elif defined _XBOX_ONE + SetTMSAction(i,eTMSAction_TMSPP_GlobalFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_Title,eTMSAction_TMSPP_RetrieveUserFilelist_DLCFileOnly); +#else + SetTMSAction(i,eTMSAction_TMSPP_DLCFileOnly); +#endif + break; + case eTMSAction_TMSPP_RetrieveUserFilelist_DLCFileOnly: +#if defined _XBOX + SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,"\\",eTMSAction_TMSPP_XUIDSFile); +#elif defined _XBOX_ONE + //StorageManager.TMSPP_DeleteFile(i,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"TP06.png",NULL,NULL, 0); + SetTMSAction(i,eTMSAction_TMSPP_UserFileList_Waiting); + app.TMSPP_RetrieveFileList(i,C4JStorage::eGlobalStorage_TitleUser,eTMSAction_TMSPP_DLCFileOnly); +#else + SetTMSAction(i,eTMSAction_TMSPP_DLCFileOnly); +#endif + + break; + + case eTMSAction_TMSPP_DLCFileOnly: +#if defined _XBOX || defined _XBOX_ONE + SetTMSAction(i,eTMSAction_TMSPP_DLCFile_Waiting); + // pass in the next app action on the call or callback completing + app.TMSPP_ReadDLCFile(i,eTMSAction_TMSPP_RetrieveFiles_Complete); +#else + SetTMSAction(i,eTMSAction_TMSPP_RetrieveFiles_Complete); +#endif + break; + + + case eTMSAction_TMSPP_RetrieveFiles_Complete: + SetTMSAction(i,eTMSAction_Idle); + break; + + + // TMS files +/* case eTMSAction_TMS_RetrieveFiles_CreateLoad_SignInReturned: + case eTMSAction_TMS_RetrieveFiles_RunPlayGame: +#ifdef _XBOX + SetTMSAction(i,eTMSAction_TMS_XUIDSFile_Waiting); + // pass in the next app action on the call or callback completing + app.ReadXuidsFileFromTMS(i,eTMSAction_TMS_DLCFile,true); +#else + SetTMSAction(i,eTMSAction_TMS_DLCFile); +#endif + break; + + case eTMSAction_TMS_DLCFile: +#ifdef _XBOX + SetTMSAction(i,eTMSAction_TMS_DLCFile_Waiting); + // pass in the next app action on the call or callback completing + app.ReadDLCFileFromTMS(i,eTMSAction_TMS_BannedListFile,true); +#else + SetTMSAction(i,eTMSAction_TMS_BannedListFile); +#endif + + break; + + case eTMSAction_TMS_RetrieveFiles_HelpAndOptions: + case eTMSAction_TMS_RetrieveFiles_DLCMain: +#ifdef _XBOX + SetTMSAction(i,eTMSAction_TMS_DLCFile_Waiting); + // pass in the next app action on the call or callback completing + app.ReadDLCFileFromTMS(i,eTMSAction_Idle,true); +#else + SetTMSAction(i,eTMSAction_Idle); +#endif + + break; + case eTMSAction_TMS_BannedListFile: +#ifdef _XBOX + SetTMSAction(i,eTMSAction_TMS_BannedListFile_Waiting); + // pass in the next app action on the call or callback completing + app.ReadBannedList(i, eTMSAction_TMS_RetrieveFiles_Complete,true); +#else + SetTMSAction(i,eTMSAction_TMS_RetrieveFiles_Complete); +#endif + + break; + + */ + case eTMSAction_TMS_RetrieveFiles_Complete: + SetTMSAction(i,eTMSAction_Idle); + // if(StorageManager.SetSaveDevice(&CScene_Main::DeviceSelectReturned,pClass)) + // { + // // save device already selected + // // ensure we've applied this player's settings + // app.ApplyGameSettingsChanged(ProfileManager.GetPrimaryPad()); + // app.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_MultiGameJoinLoad); + // } + break; + } + } + + } +} + +int CMinecraftApp::BannedLevelDialogReturned(void *pParam,int iPad,const C4JStorage::EMessageResult result) +{ + CMinecraftApp* pApp = (CMinecraftApp*)pParam; + //Minecraft *pMinecraft=Minecraft::GetInstance(); + + if(result==C4JStorage::EMessage_ResultAccept) + { +#if defined _XBOX || defined _XBOX_ONE + INetworkPlayer *pHost = g_NetworkManager.GetHostPlayer(); + // unban the level + if (pHost != NULL) + { +#if defined _XBOX + pApp->RemoveLevelFromBannedLevelList(iPad,((NetworkPlayerXbox *)pHost)->GetUID(),pApp->GetUniqueMapName()); +#else + pApp->RemoveLevelFromBannedLevelList(iPad,pHost->GetUID(),pApp->GetUniqueMapName()); +#endif + } +#endif + } + else + { + if( iPad == ProfileManager.GetPrimaryPad() ) + { + pApp->SetAction(iPad,eAppAction_ExitWorld); + } + else + { + pApp->SetAction(iPad,eAppAction_ExitPlayer); + } + } + + return 0; +} + +void CMinecraftApp::loadMediaArchive() +{ + wstring mediapath = L""; + +#ifdef __PS3__ + mediapath = L"Common\\Media\\MediaPS3.arc"; +#elif _WINDOWS64 + mediapath = L"Common\\Media\\MediaWindows64.arc"; +#elif __ORBIS__ + mediapath = L"Common\\Media\\MediaOrbis.arc"; +#elif _DURANGO + mediapath = L"Common\\Media\\MediaDurango.arc"; +#elif __PSVITA__ + mediapath = L"Common\\Media\\MediaPSVita.arc"; +#endif + + if (!mediapath.empty()) + { + m_mediaArchive = new ArchiveFile( File(mediapath) ); + } +#if 0 + string path = "Common\\media.arc"; + HANDLE hFile = CreateFile( path.c_str(), + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_FLAG_SEQUENTIAL_SCAN, + NULL ); + + if( hFile != INVALID_HANDLE_VALUE ) + { + File fileHelper(convStringToWstring(path)); + DWORD dwFileSize = fileHelper.length(); + + // Initialize memory. + PBYTE m_fBody = new BYTE[ dwFileSize ]; + ZeroMemory(m_fBody, dwFileSize); + + DWORD m_fSize = 0; + BOOL hr = ReadFile( hFile, + m_fBody, + dwFileSize, + &m_fSize, + NULL ); + + assert( m_fSize == dwFileSize ); + + CloseHandle( hFile ); + + m_mediaArchive = new ArchiveFile(m_fBody, m_fSize); + } + else + { + assert( false ); + // AHHHHHHHHHHHH + m_mediaArchive = NULL; + } +#endif +} + +void CMinecraftApp::loadStringTable() +{ +#ifndef _XBOX + + if(m_stringTable!=NULL) + { + // we need to unload the current string table, this is a reload + delete m_stringTable; + } + wstring localisationFile = L"languages.loc"; + if (m_mediaArchive->hasFile(localisationFile)) + { + byteArray locFile = m_mediaArchive->getFile(localisationFile); + m_stringTable = new StringTable(locFile.data, locFile.length); + delete locFile.data; + } + else + { + m_stringTable = NULL; + assert(false); + // AHHHHHHHHH. + } +#endif +} + +int CMinecraftApp::PrimaryPlayerSignedOutReturned(void *pParam,int iPad,const C4JStorage::EMessageResult) +{ + //CMinecraftApp* pApp = (CMinecraftApp*)pParam; + //Minecraft *pMinecraft=Minecraft::GetInstance(); + + // if the player is null, we're in the menus + //if(Minecraft::GetInstance()->player!=NULL) + + // We always create a session before kicking of any of the game code, so even though we may still be joining/creating a game + // at this point we want to handle it differently from just being in a menu + if( g_NetworkManager.IsInSession() ) + { + app.SetAction(iPad,eAppAction_PrimaryPlayerSignedOutReturned); + } + else + { + app.SetAction(iPad,eAppAction_PrimaryPlayerSignedOutReturned_Menus); + } + return 0; +} + +int CMinecraftApp::EthernetDisconnectReturned(void *pParam,int iPad,const C4JStorage::EMessageResult) +{ + //CMinecraftApp* pApp = (CMinecraftApp*)pParam; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + // if the player is null, we're in the menus + if(Minecraft::GetInstance()->player!=NULL) + { + app.SetAction(pMinecraft->player->GetXboxPad(),eAppAction_EthernetDisconnectedReturned); + } + else + { + // 4J-PB - turn off the PSN store icon just in case this happened when we were in one of the DLC menus +#ifdef __ORBIS__ + sceNpCommerceHidePsStoreIcon(); +#elif defined __PSVITA__ + sceNpCommerce2HidePsStoreIcon(); +#endif + app.SetAction(iPad,eAppAction_EthernetDisconnectedReturned_Menus); + } + return 0; +} + +int CMinecraftApp::SignoutExitWorldThreadProc( void* lpParameter ) +{ + + // Share AABB & Vec3 pools with default (main thread) - should be ok as long as we don't tick the main thread whilst this thread is running + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + + //app.SetGameStarted(false); + + Minecraft *pMinecraft=Minecraft::GetInstance(); + + int exitReasonStringId = -1; + + bool saveStats = false; + if (pMinecraft->isClientSide() || g_NetworkManager.IsInSession() ) + { + if(lpParameter != NULL ) + { + switch( app.GetDisconnectReason() ) + { + case DisconnectPacket::eDisconnect_Kicked: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + case DisconnectPacket::eDisconnect_NoUGC_AllLocal: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + break; + case DisconnectPacket::eDisconnect_NoUGC_Single_Local: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + break; +#ifdef _XBOX + case DisconnectPacket::eDisconnect_NoUGC_Remote: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; + break; +#endif + case DisconnectPacket::eDisconnect_NoFlying: + exitReasonStringId = IDS_DISCONNECTED_FLYING; + break; + case DisconnectPacket::eDisconnect_OutdatedServer: + exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; + break; + case DisconnectPacket::eDisconnect_OutdatedClient: + exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; + break; + default: + exitReasonStringId = IDS_DISCONNECTED; + } + pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId ); + // 4J - Force a disconnection, this handles the situation that the server has already disconnected + if( pMinecraft->levels[0] != NULL ) pMinecraft->levels[0]->disconnect(false); + if( pMinecraft->levels[1] != NULL ) pMinecraft->levels[1]->disconnect(false); + } + else + { + exitReasonStringId = IDS_EXITING_GAME; + pMinecraft->progressRenderer->progressStartNoAbort( IDS_EXITING_GAME ); + + if( pMinecraft->levels[0] != NULL ) pMinecraft->levels[0]->disconnect(); + if( pMinecraft->levels[1] != NULL ) pMinecraft->levels[1]->disconnect(); + } + + // 4J Stu - This only does something if we actually have a server, so don't need to do any other checks + MinecraftServer::HaltServer(true); + + // We need to call the stats & leaderboards save before we exit the session + //pMinecraft->forceStatsSave(); + saveStats = false; + + // 4J Stu - Leave the session once the disconnect packet has been sent + g_NetworkManager.LeaveGame(FALSE); + } + else + { + if(lpParameter != NULL ) + { + switch( app.GetDisconnectReason() ) + { + case DisconnectPacket::eDisconnect_Kicked: + exitReasonStringId = IDS_DISCONNECTED_KICKED; + break; + case DisconnectPacket::eDisconnect_NoUGC_AllLocal: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + break; + case DisconnectPacket::eDisconnect_NoUGC_Single_Local: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + break; +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) + case DisconnectPacket::eDisconnect_ContentRestricted_AllLocal: + exitReasonStringId = IDS_CONTENT_RESTRICTION_MULTIPLAYER; + break; + case DisconnectPacket::eDisconnect_ContentRestricted_Single_Local: + exitReasonStringId = IDS_CONTENT_RESTRICTION; + break; +#endif +#ifdef _XBOX + case DisconnectPacket::eDisconnect_NoUGC_Remote: + exitReasonStringId = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_REMOTE; + break; +#endif + case DisconnectPacket::eDisconnect_OutdatedServer: + exitReasonStringId = IDS_DISCONNECTED_SERVER_OLD; + break; + case DisconnectPacket::eDisconnect_OutdatedClient: + exitReasonStringId = IDS_DISCONNECTED_CLIENT_OLD; + default: + exitReasonStringId = IDS_DISCONNECTED; + } + pMinecraft->progressRenderer->progressStartNoAbort( exitReasonStringId ); + } + } + pMinecraft->setLevel(NULL,exitReasonStringId,nullptr,saveStats,true); + + // 4J-JEV: Fix for #106402 - TCR #014 BAS Debug Output: + // TU12: Mass Effect Mash-UP: Save file "Default_DisplayName" is created on all storage devices after signing out from a re-launched pre-generated world + app.m_gameRules.unloadCurrentGameRules(); // + + MinecraftServer::resetFlags(); + + // We can't start/join a new game until the session is destroyed, so wait for it to be idle again + while( g_NetworkManager.IsInSession() ) + { + Sleep(1); + } + + return S_OK; +} + +int CMinecraftApp::UnlockFullInviteReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + //CMinecraftApp* pApp = (CMinecraftApp*)pParam; + Minecraft *pMinecraft=Minecraft::GetInstance(); + bool bNoPlayer; + + // bug 11285 - TCR 001: BAS Game Stability: CRASH - When trying to join a full version game with a trial version, the trial crashes + // 4J-PB - we may be in the main menus here, and we don't have a pMinecraft->player + + if(pMinecraft->player==NULL) + { + bNoPlayer=true; + } + + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedInLive(iPad)) + { + // 4J-PB - need to check this user can access the store +#if defined(__PS3__) || defined(__PSVITA__) + bool bContentRestricted; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL); + if(bContentRestricted) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable()); + } + else +#endif + { + ProfileManager.DisplayFullVersionPurchase(false,iPad,eSen_UpsellID_Full_Version_Of_Game); + } + } +#if defined(__PS3__) + else + { + // you're not signed in to PSN! + UINT uiIDA[2]; + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable()); + + } +#endif + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined); + } + + return 0; +} + +int CMinecraftApp::UnlockFullSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + //CMinecraftApp* pApp = (CMinecraftApp*)pParam; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedInLive(pMinecraft->player->GetXboxPad())) + { + // 4J-PB - need to check this user can access the store +#if defined(__PS3__) || defined(__PSVITA__) + bool bContentRestricted; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL); + if(bContentRestricted) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable()); + } + else +#endif + { + ProfileManager.DisplayFullVersionPurchase(false,pMinecraft->player->GetXboxPad(),eSen_UpsellID_Full_Version_Of_Game); + } + } +#if defined(__PS3__) + else + { + // you're not signed in to PSN! + UINT uiIDA[2]; + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable()); + } +#elif defined(__ORBIS__) + else + { + // Determine why they're not "signed in live" + if (ProfileManager.isSignedInPSN(iPad)) + { + // Signed in to PSN but not connected (no internet access) + assert(!ProfileManager.isConnectedToPSN(iPad)); + + UINT uiIDA[1]; + uiIDA[0] = IDS_OK; + ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable()); + } + else + { + // Not signed in to PSN + UINT uiIDA[1]; + uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT; + ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPad, &CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable(), NULL, 0, false); + } + } +#endif + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined); + } + + return 0; +} + +int CMinecraftApp::UnlockFullExitReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CMinecraftApp* pApp = (CMinecraftApp*)pParam; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedInLive(pMinecraft->player->GetXboxPad())) + { + // 4J-PB - need to check this user can access the store +#if defined(__PS3__) || defined(__PSVITA__) + bool bContentRestricted; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL); + if(bContentRestricted) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable()); + } + else +#endif + { + ProfileManager.DisplayFullVersionPurchase(false,pMinecraft->player->GetXboxPad(),eSen_UpsellID_Full_Version_Of_Game); +#if defined __ORBIS__ || defined __PS3__ || defined __PSVITA__ + // still need to exit the trial or we'll be in the Pause menu with input ignored + pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial); +#endif + } + } +#if defined(__PS3__) || defined __PSVITA__ + else + { + // you're not signed in to PSN! + UINT uiIDA[2]; + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial,&app, app.GetStringTable()); + } +#elif defined(__ORBIS__) + else + { + // Determine why they're not "signed in live" + if (ProfileManager.isSignedInPSN(iPad)) + { + // Signed in to PSN but not connected (no internet access) + assert(!ProfileManager.isConnectedToPSN(iPad)); + + UINT uiIDA[1]; + uiIDA[0] = IDS_OK; + ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable()); + // still need to exit the trial or we'll be in the Pause menu with input ignored + pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial); + } + else + { + // Not signed in to PSN + UINT uiIDA[1]; + uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT; + ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPad, &CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial,&app, app.GetStringTable(), NULL, 0, false); + } + } +#endif + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined); + pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial); + } + + return 0; +} + +int CMinecraftApp::TrialOverReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CMinecraftApp* pApp = (CMinecraftApp*)pParam; + Minecraft *pMinecraft=Minecraft::GetInstance(); + + if(result==C4JStorage::EMessage_ResultAccept) + { + // we need a signed in user for the unlock + if(ProfileManager.IsSignedInLive(pMinecraft->player->GetXboxPad())) + { + // 4J-PB - need to check this user can access the store +#if defined(__PS3__) || defined(__PSVITA__) + bool bContentRestricted; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),true,NULL,&bContentRestricted,NULL); + if(bContentRestricted) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable()); + } + else +#endif + { + ProfileManager.DisplayFullVersionPurchase(false,pMinecraft->player->GetXboxPad(),eSen_UpsellID_Full_Version_Of_Game); + } + } + else + { +#if defined(__PS3__) + + // you're not signed in to PSN! + UINT uiIDA[2]; + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable()); + + // 4J Stu - We can't actually exit the game, so just exit back to the main menu + //pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial); +#else + pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitTrial); +#endif + } + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, eSen_UpsellOutcome_Declined); + +#if defined(__PS3__) || defined(__ORBIS__) + // 4J Stu - We can't actually exit the game, so just exit back to the main menu + pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitWorldTrial); +#else + pApp->SetAction(pMinecraft->player->GetXboxPad(),eAppAction_ExitTrial); +#endif + } + + return 0; +} + +void CMinecraftApp::ProfileReadErrorCallback(void *pParam) +{ + CMinecraftApp *pApp=(CMinecraftApp *)pParam; + int iPrimaryPlayer=ProfileManager.GetPrimaryPad(); + pApp->SetAction(iPrimaryPlayer, eAppAction_ProfileReadError); +} + +void CMinecraftApp::ClearSignInChangeUsersMask() +{ + // 4J-PB - When in the main menu, the user is on pad 0, and any change they make to their profile will be to pad 0 data + // If they then go in as a secondary player to a splitscreen game, their profile will not be read again on pad 1 if they were previously in a splitscreen game + // This is because m_uiLastSignInData remembers they were in previously, and doesn't read the profile data for them again + // Fix this by resetting the m_uiLastSignInData on pressing play game for secondary users. The Primary user does a read profile on play game anyway + int iPrimaryPlayer=ProfileManager.GetPrimaryPad(); + + if(m_uiLastSignInData!=0) + { + if(iPrimaryPlayer>=0) + { + m_uiLastSignInData=1<user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); +#endif + + CMinecraftApp *pApp=(CMinecraftApp *)pParam; + // check if the primary player signed out + int iPrimaryPlayer=ProfileManager.GetPrimaryPad(); + + if((ProfileManager.GetLockedProfile()!=-1) && iPrimaryPlayer!=-1) + { + if ( ((uiSignInData & (1<SetAction(iPrimaryPlayer,eAppAction_PrimaryPlayerSignedOut); + + // 4J-PB - invalidate their banned level list + pApp->InvalidateBannedList(iPrimaryPlayer); + + // need to ditch any DLCOffers info + StorageManager.ClearDLCOffers(); + pApp->ClearAndResetDLCDownloadQueue(); + pApp->ClearDLCInstalled(); + } + else + { + unsigned int uiChangedPlayers = uiSignInData ^ m_uiLastSignInData; + + if( g_NetworkManager.IsInSession() ) + { + bool hasGuestIdChanged = false; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + DWORD guestNumber = 0; + if(ProfileManager.IsSignedIn(i)) + { + XUSER_SIGNIN_INFO info; + XUserGetSigninInfo(i,XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY ,&info); + pApp->DebugPrintf("Player at index %d has guest number %d\n", i,info.dwGuestNumber ); + guestNumber = info.dwGuestNumber; + } + if( pApp->m_currentSigninInfo[i].dwGuestNumber != 0 && guestNumber != 0 && pApp->m_currentSigninInfo[i].dwGuestNumber != guestNumber ) + { + hasGuestIdChanged = true; + } + } + + if( hasGuestIdChanged ) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_GUEST_ORDER_CHANGED_TITLE, IDS_GUEST_ORDER_CHANGED_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,NULL,app.GetStringTable()); + } + + // 4J Stu - On PS4 we can also cause to exit players if they are signed out here, but we shouldn't do that if + // we are going to switch to an offline game as it will likely crash due to incompatible parallel processes + bool switchToOffline = false; + // If it's an online game, and the primary profile is no longer signed into LIVE then we act as if disconnected + if( !ProfileManager.IsSignedInLive( ProfileManager.GetLockedProfile() ) && !g_NetworkManager.IsLocalGame() ) + { + switchToOffline = true; + } + + //printf("Old: %x, New: %x, Changed: %x\n", m_ulLastSignInData, ulSignInData, changedPlayers); + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + // Primary player shouldn't be subjected to these checks, and shouldn't call ExitPlayer + if(i == iPrimaryPlayer) continue; + + // A guest a signed in or out, out of order which invalidates all the guest players we have in the game + if(hasGuestIdChanged && pApp->m_currentSigninInfo[i].dwGuestNumber != 0 && g_NetworkManager.GetLocalPlayerByUserIndex(i)!=NULL) + { + pApp->DebugPrintf("Recommending removal of player at index %d because their guest id changed\n",i); + pApp->SetAction(i,eAppAction_ExitPlayer); + } + else + { + XUSER_SIGNIN_INFO info; + XUserGetSigninInfo(i,XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY ,&info); + // 4J Stu - Also need to detect the case where the sign in mask is the same, but the player has swapped users (eg still signed in but xuid different) + // Fix for #48451 - TU5: Code: UI: Splitscreen: Title crashes when switching to a profile previously signed out via splitscreen profile selection + + // 4J-PB - compiler complained about if below ('&&' within '||') - making it easier to read + bool bPlayerChanged=(uiChangedPlayers&(1<m_currentSigninInfo[i].xuid, info.xuid) ) )) + { + // 4J-PB - invalidate their banned level list + pApp->DebugPrintf("Player at index %d Left - invalidating their banned list\n",i); + pApp->InvalidateBannedList(i); + + if(g_NetworkManager.GetLocalPlayerByUserIndex(i)!=NULL) + { + pApp->DebugPrintf("Player %d signed out\n", i); + pApp->SetAction(i,eAppAction_ExitPlayer); + } + } + } +#ifdef __ORBIS__ + // check if any of the addition players have signed out of PSN (primary player is handled below) + if(!switchToOffline && i != ProfileManager.GetLockedProfile() && !g_NetworkManager.IsLocalGame()) + { + if(g_NetworkManager.GetLocalPlayerByUserIndex(i)!=NULL) + { + if(ProfileManager.IsSignedInLive(i) == false) + { + pApp->DebugPrintf("Recommending removal of player at index %d because they're no longer signed into PSNd\n",i); + pApp->SetAction(i,eAppAction_ExitPlayer); + } + } + } +#endif + } + + // If it's an online game, and the primary profile is no longer signed into LIVE then we act as if disconnected + if( switchToOffline ) + { + pApp->SetAction(iPrimaryPlayer,eAppAction_EthernetDisconnected); + } + + + g_NetworkManager.HandleSignInChange(); + } + // Some menus require the player to be signed in to live, so if this callback happens and the primary player is + // no longer signed in then nav back + else if ( pApp->GetLiveLinkRequired() && !ProfileManager.IsSignedInLive( ProfileManager.GetLockedProfile() ) ) + { + pApp->SetAction(iPrimaryPlayer,eAppAction_EthernetDisconnected); + } + +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__ ) + // 4J-JEV: Need to kick of loading of profile data for sub-sign in players. + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( i != iPrimaryPlayer + && ( uiChangedPlayers & (1<InvalidateBannedList(iPrimaryPlayer); + + // need to ditch any DLCOffers info + StorageManager.ClearDLCOffers(); + pApp->ClearAndResetDLCDownloadQueue(); + pApp->ClearDLCInstalled(); + + } + + // Update the guest numbers to the current state + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if(FAILED(XUserGetSigninInfo(i,XUSER_GET_SIGNIN_INFO_OFFLINE_XUID_ONLY,&pApp->m_currentSigninInfo[i]))) + { + pApp->m_currentSigninInfo[i].xuid = INVALID_XUID; + pApp->m_currentSigninInfo[i].dwGuestNumber = 0; + } + app.DebugPrintf("Player at index %d has guest number %d\n", i,pApp->m_currentSigninInfo[i].dwGuestNumber ); + } +} + +void CMinecraftApp::NotificationsCallback(LPVOID pParam,DWORD dwNotification, unsigned int uiParam) +{ + CMinecraftApp* pClass = (CMinecraftApp*)pParam; + + // push these on to the notifications to be handled in qnet's dowork + + PNOTIFICATION pNotification = new NOTIFICATION; + + pNotification->dwNotification=dwNotification; + pNotification->uiParam=uiParam; + + switch( dwNotification ) + { + case XN_SYS_SIGNINCHANGED: + { + pClass->DebugPrintf("Signing changed - %d\n", uiParam ); + } + break; + case XN_SYS_INPUTDEVICESCHANGED: + if(app.GetGameStarted() && g_NetworkManager.IsInSession()) + { + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if(!InputManager.IsPadConnected(i) && + Minecraft::GetInstance()->localplayers[i] != NULL && + !ui.IsPauseMenuDisplayed(i) && !ui.IsSceneInStack(i, eUIScene_EndPoem) ) + { + ui.CloseUIScenes(i); + ui.NavigateToScene(i,eUIScene_PauseMenu); + } + } + } + break; + case XN_LIVE_CONTENT_INSTALLED: + // Need to inform xuis that we've possibly had DLC installed + { + //app.m_dlcManager.SetNeedsUpdated(true); + // Clear the DLC installed flag to cause a GetDLC to run if it's called + app.ClearDLCInstalled(); + + ui.HandleDLCInstalled(ProfileManager.GetPrimaryPad()); + } + break; + case XN_SYS_STORAGEDEVICESCHANGED: + { +#ifdef _XBOX + // If the devices have changed, and we've got a dlc pack with audio selected, and that pack's content device is no longer valid... then pull the plug on + // audio streaming, as if we leave this until later xact gets locked up attempting to destroy the streamed wave bank. + TexturePack *pTexPack=Minecraft::GetInstance()->skins->getSelected(); + if(pTexPack->hasAudio()) + { + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)pTexPack; + XCONTENTDEVICEID deviceID = pDLCTexPack->GetDLCDeviceID(); + if( XContentGetDeviceState( deviceID, NULL ) != ERROR_SUCCESS ) + { + // Set texture pack flag so that it is now considered as not having audio - this is critical so that the next playStreaming does what it is meant to do, + // and also so that we don't try and unmount this again, or play any sounds from it in the future + pTexPack->setHasAudio(false); + // need to stop the streaming audio - by playing streaming audio from the default texture pack now + Minecraft::GetInstance()->soundEngine->playStreaming(L"", 0, 0, 0, 0, 0); + + if(pDLCTexPack->m_pStreamedWaveBank!=NULL) + { + pDLCTexPack->m_pStreamedWaveBank->Destroy(); + } + if(pDLCTexPack->m_pSoundBank!=NULL) + { + pDLCTexPack->m_pSoundBank->Destroy(); + } + DWORD result = StorageManager.UnmountInstalledDLC("TPACK"); + app.DebugPrintf("Unmount result is %d\n",result); + } + } +#endif + } + break; + } + + pClass->m_vNotifications.push_back(pNotification); +} + +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ +int CMinecraftApp::MustSignInFullVersionPurchaseReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + if(result==C4JStorage::EMessage_ResultAccept) + { +#ifdef __PS3__ + SQRNetworkManager_PS3::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true); +#elif defined __PSVITA__ + SQRNetworkManager_Vita::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true); +#else // __PS4__ + SQRNetworkManager_Orbis::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true); +#endif + } + + return 0; +} + +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ +int CMinecraftApp::MustSignInFullVersionPurchaseReturnedExitTrial(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + if(result==C4JStorage::EMessage_ResultAccept) + { +#ifdef __PS3__ + SQRNetworkManager_PS3::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true); +#elif defined __PSVITA__ + SQRNetworkManager_Vita::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true); +#else // __PS4__ + SQRNetworkManager_Orbis::AttemptPSNSignIn(&CMinecraftApp::NowDisplayFullVersionPurchase, &app,true); +#endif + } + + //4J-PB - we need to exit the trial, or we'll be in the pause menu with ignore input true + app.SetAction(iPad,eAppAction_ExitWorldTrial); + + return 0; +} +#endif + +int CMinecraftApp::NowDisplayFullVersionPurchase(void *pParam, bool bContinue, int iPad) +{ + app.m_bDisplayFullVersionPurchase=true; + return 0; +} +#endif +void CMinecraftApp::UpsellReturnedCallback(LPVOID pParam, eUpsellType type, eUpsellResponse result, int iUserData) +{ + ESen_UpsellID senType; + ESen_UpsellOutcome senResponse; +#ifdef __PS3__ + UINT uiIDA[2]; +#endif + + // Map the eUpsellResponse to the enum we use for sentient + switch(result) + { + case eUpsellResponse_Accepted_NoPurchase: + senResponse = eSen_UpsellOutcome_Went_To_Guide; + break; + case eUpsellResponse_Accepted_Purchase: + senResponse = eSen_UpsellOutcome_Accepted; + break; +#ifdef __PS3__ + // special case for people who are not signed in to the PSN while playing the trial game + case eUpsellResponse_UserNotSignedInPSN: + + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::MustSignInFullVersionPurchaseReturned,&app, app.GetStringTable()); + + return; + + case eUpsellResponse_NotAllowedOnline: // On earning a trophy in the trial version, where the user is underage and can't go online to buy the game, but they selected to buy the game on the trophy upsell + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, ProfileManager.GetPrimaryPad(),NULL,&app, app.GetStringTable()); + break; +#endif + case eUpsellResponse_Declined: + default: + senResponse = eSen_UpsellOutcome_Declined; + break; + }; + + // Map the eUpsellType to the enum we use for sentient + switch(type) + { + case eUpsellType_Custom: + senType = eSen_UpsellID_Full_Version_Of_Game; + break; + default: + senType = eSen_UpsellID_Undefined; + break; + }; + + // Always the primary pad that gets an upsell + TelemetryManager->RecordUpsellResponded(ProfileManager.GetPrimaryPad(), eSen_UpsellID_Full_Version_Of_Game, app.m_dwOfferID, senResponse); +} + +void CMinecraftApp::SetDebugSequence(const char *pchSeq) +{ + InputManager.SetDebugSequence(pchSeq,&CMinecraftApp::DebugInputCallback,this); +} +int CMinecraftApp::DebugInputCallback(LPVOID pParam) +{ + CMinecraftApp* pClass = (CMinecraftApp*)pParam; + //printf("sequence matched\n"); + pClass->m_bDebugOptions=!pClass->m_bDebugOptions; + + for(int i=0;ilocalplayers[i] != NULL) + { + iPlayerC++; + } + } + + return iPlayerC; +} + +int CMinecraftApp::MarketplaceCountsCallback(LPVOID pParam,C4JStorage::DLC_TMS_DETAILS *pTMSDetails, int iPad) +{ + app.DebugPrintf("Marketplace Counts= New - %d Total - %d\n",pTMSDetails->dwNewOffers,pTMSDetails->dwTotalOffers); + + if(pTMSDetails->dwNewOffers>0) + { + app.m_bNewDLCAvailable=true; + app.m_bSeenNewDLCTip=false; + } + else + { + app.m_bNewDLCAvailable=false; + app.m_bSeenNewDLCTip=true; + } + + return 0; +} + +bool CMinecraftApp::StartInstallDLCProcess(int iPad) +{ + app.DebugPrintf("--- CMinecraftApp::StartInstallDLCProcess: pad=%i.\n", iPad); + + // If there is already a call to this in progress, then do nothing + // If the app says dlc is installed, then there has been no new system message to tell us there's new DLC since the last call to StartInstallDLCProcess + if((app.DLCInstallProcessCompleted()==false) && (m_bDLCInstallPending==false)) + { + app.m_dlcManager.resetUnnamedCorruptCount(); + m_bDLCInstallPending = true; + m_iTotalDLC = 0; + m_iTotalDLCInstalled = 0; + app.DebugPrintf("--- CMinecraftApp::StartInstallDLCProcess - StorageManager.GetInstalledDLC\n"); + + StorageManager.GetInstalledDLC(iPad,&CMinecraftApp::DLCInstalledCallback,this); + return true; + } + else + { + app.DebugPrintf("--- CMinecraftApp::StartInstallDLCProcess - nothing to do\n"); + + return false; + } + +} + +// Installed DLC callback +int CMinecraftApp::DLCInstalledCallback(LPVOID pParam,int iInstalledC,int iPad) +{ + app.DebugPrintf("--- CMinecraftApp::DLCInstalledCallback: totalDLC=%i, pad=%i.\n", iInstalledC, iPad); + app.m_iTotalDLC = iInstalledC; + app.MountNextDLC(iPad); + return 0; +} + +void CMinecraftApp::MountNextDLC(int iPad) +{ + app.DebugPrintf("--- CMinecraftApp::MountNextDLC: pad=%i.\n", iPad); + if(m_iTotalDLCInstalled < m_iTotalDLC) + { + // Mount it + // We also need to match the ones the user wants to mount with the installed DLC + // We're supposed to use a generic save game as a cache of these to do this, with XUSER_ANY + + if(StorageManager.MountInstalledDLC(iPad,m_iTotalDLCInstalled,&CMinecraftApp::DLCMountedCallback,this)!=ERROR_IO_PENDING ) + { + // corrupt DLC + app.DebugPrintf("Failed to mount DLC %d for pad %d\n",m_iTotalDLCInstalled,iPad); + ++m_iTotalDLCInstalled; + app.MountNextDLC(iPad); + } + else + { + app.DebugPrintf("StorageManager.MountInstalledDLC ok\n"); + } + } + else + { + /* Removed - now loading these on demand instead of as each pack is mounted + if(m_iTotalDLCInstalled > 0) + { + Minecraft *pMinecraft=Minecraft::GetInstance(); + pMinecraft->levelRenderer->AddDLCSkinsToMemTextures(); + } + */ + + m_bDLCInstallPending = false; + m_bDLCInstallProcessCompleted=true; + + ui.HandleDLCMountingComplete(); + +#if defined(_XBOX_ONE) || defined(__ORBIS__) + // Check if the current texture pack is now installed + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + + DLCPack *pParentPack=pDLCTexPack->getDLCInfoParentPack();//tPack->getDLCPack(); + + if(pParentPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + StorageManager.SetSaveDisabled(false); + } + } +#endif + } +} + +// 4J-JEV: For the sake of clarity in DLCMountedCallback. +#if defined(_XBOX) || defined(__PS3__) || defined(_WINDOWS64) +#define CONTENT_DATA_DISPLAY_NAME(a) (a.szDisplayName) +#else +#define CONTENT_DATA_DISPLAY_NAME(a) (a.wszDisplayName) +#endif + +int CMinecraftApp::DLCMountedCallback(LPVOID pParam,int iPad,DWORD dwErr,DWORD dwLicenceMask) +{ +#if defined(_XBOX) || defined(_DURANGO) || defined(__PS3__) || defined(__ORBIS__) || defined(_WINDOWS64) || defined (__PSVITA__) //Chris TODO + app.DebugPrintf("--- CMinecraftApp::DLCMountedCallback\n"); + + if(dwErr!=ERROR_SUCCESS) + { + // corrupt DLC + app.DebugPrintf("Failed to mount DLC for pad %d: %d\n",iPad,dwErr); + app.m_dlcManager.incrementUnnamedCorruptCount(); + } + else + { + XCONTENT_DATA ContentData = StorageManager.GetDLC(app.m_iTotalDLCInstalled); + + DLCPack *pack = app.m_dlcManager.getPack( CONTENT_DATA_DISPLAY_NAME(ContentData) ); + + if( pack != NULL && pack->IsCorrupt() ) + { + app.DebugPrintf("Pack '%ls' is corrupt, removing it from the DLC Manager.\n", CONTENT_DATA_DISPLAY_NAME(ContentData)); + + app.m_dlcManager.removePack(pack); + pack = NULL; + } + + if(pack == NULL) + { + app.DebugPrintf("Pack \"%ls\" is not installed, so adding it\n", CONTENT_DATA_DISPLAY_NAME(ContentData)); + +#if defined(_XBOX) || defined(__PS3__) || defined(_WINDOWS64) + pack = new DLCPack(ContentData.szDisplayName,dwLicenceMask); +#elif defined _XBOX_ONE + pack = new DLCPack(ContentData.wszDisplayName,ContentData.wszProductID,dwLicenceMask); +#else + pack = new DLCPack(ContentData.wszDisplayName,dwLicenceMask); +#endif + pack->SetDLCMountIndex(app.m_iTotalDLCInstalled); + pack->SetDLCDeviceID(ContentData.DeviceID); + app.m_dlcManager.addPack(pack); + + app.HandleDLC(pack); + + if(pack->getDLCItemsCount(DLCManager::e_DLCType_Texture) > 0) + { + Minecraft::GetInstance()->skins->addTexturePackFromDLC(pack, pack->GetPackId() ); + } + } + else + { + app.DebugPrintf("Pack \"%ls\" is already installed. Updating license to %d\n", CONTENT_DATA_DISPLAY_NAME(ContentData), dwLicenceMask); + + pack->SetDLCMountIndex(app.m_iTotalDLCInstalled); + pack->SetDLCDeviceID(ContentData.DeviceID); + pack->updateLicenseMask(dwLicenceMask); + } + + StorageManager.UnmountInstalledDLC(); + } + ++app.m_iTotalDLCInstalled; + app.MountNextDLC(iPad); + +#endif // __PSVITA__ + return 0; +} +#undef CONTENT_DATA_DISPLAY_NAME + +// void CMinecraftApp::InstallDefaultCape() +// { +// if(!m_bDefaultCapeInstallAttempted) +// { +// // we only attempt to install the cape once per launch of the game +// m_bDefaultCapeInstallAttempted=true; +// +// wstring wTemp=L"Default_Cape.png"; +// bool bRes=app.IsFileInMemoryTextures(wTemp); +// // if the file is not already in the memory textures, then read it from TMS +// if(!bRes) +// { +// BYTE *pBuffer=NULL; +// DWORD dwSize=0; +// // 4J-PB - out for now for DaveK so he doesn't get the birthday cape +// #ifdef _CONTENT_PACKAGE +// C4JStorage::ETMSStatus eTMSStatus; +// eTMSStatus=StorageManager.ReadTMSFile(ProfileManager.GetPrimaryPad(),C4JStorage::eGlobalStorage_Title,C4JStorage::eTMS_FileType_Graphic, L"Default_Cape.png",&pBuffer, &dwSize); +// if(eTMSStatus==C4JStorage::ETMSStatus_Idle) +// { +// app.AddMemoryTextureFile(wTemp,pBuffer,dwSize); +// } +// #endif +// } +// } +// } + + void CMinecraftApp::HandleDLC(DLCPack *pack) + { + DWORD dwFilesProcessed = 0; +#ifndef _XBOX +#if defined(__PS3__) || defined(__ORBIS__) || defined(_WINDOWS64) || defined (__PSVITA__) + std::vector dlcFilenames; +#elif defined _DURANGO + std::vector dlcFilenames; +#endif + StorageManager.GetMountedDLCFileList("DLCDrive", dlcFilenames); + for(int i=0; ieXuid==eXUID_Deadmau5) + { + return true; + } + } + + return false; +} + +void CMinecraftApp::AddMemoryTextureFile(const wstring &wName,PBYTE pbData,DWORD dwBytes) +{ + EnterCriticalSection(&csMemFilesLock); + // check it's not already in + PMEMDATA pData=NULL; + AUTO_VAR(it, m_MEM_Files.find(wName)); + if(it != m_MEM_Files.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Incrementing the memory texture file count for %ls\n", wName.c_str()); +#endif + pData = (*it).second; + + if(pData->dwBytes == 0 && dwBytes != 0) + { + // This should never be NULL if dwBytes is 0 + if(pData->pbData!=NULL) delete [] pData->pbData; + + pData->pbData=pbData; + pData->dwBytes=dwBytes; + } + + ++pData->ucRefCount; + LeaveCriticalSection(&csMemFilesLock); + return; + } + +#ifndef _CONTENT_PACKAGE + //wprintf(L"Adding the memory texture file data for %ls\n", wName.c_str()); +#endif + // this is a texture (png) file + + // add this texture to the list of memory texture files - it will then be picked up by the level renderer's AddEntity + + pData = (PMEMDATA)new BYTE[sizeof(MEMDATA)]; + ZeroMemory( pData, sizeof(MEMDATA) ); + pData->pbData=pbData; + pData->dwBytes=dwBytes; + pData->ucRefCount = 1; + + // use the xuid to access the skin data + m_MEM_Files[wName]=pData; + + LeaveCriticalSection(&csMemFilesLock); +} + +void CMinecraftApp::RemoveMemoryTextureFile(const wstring &wName) +{ + EnterCriticalSection(&csMemFilesLock); + + AUTO_VAR(it, m_MEM_Files.find(wName)); + if(it != m_MEM_Files.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Decrementing the memory texture file count for %ls\n", wName.c_str()); +#endif + PMEMDATA pData = (*it).second; + --pData->ucRefCount; + if(pData->ucRefCount <= 0) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Erasing the memory texture file data for %ls\n", wName.c_str()); +#endif + delete [] pData; + m_MEM_Files.erase(wName); + } + } + LeaveCriticalSection(&csMemFilesLock); +} + +bool CMinecraftApp::DefaultCapeExists() +{ + wstring wTex=L"Special_Cape.png"; + bool val = false; + + EnterCriticalSection(&csMemFilesLock); + AUTO_VAR(it, m_MEM_Files.find(wTex)); + if(it != m_MEM_Files.end()) val = true; + LeaveCriticalSection(&csMemFilesLock); + + return val; +} + +bool CMinecraftApp::IsFileInMemoryTextures(const wstring &wName) +{ + bool val = false; + + EnterCriticalSection(&csMemFilesLock); + AUTO_VAR(it, m_MEM_Files.find(wName)); + if(it != m_MEM_Files.end()) val = true; + LeaveCriticalSection(&csMemFilesLock); + + return val; +} + +void CMinecraftApp::GetMemFileDetails(const wstring &wName,PBYTE *ppbData,DWORD *pdwBytes) +{ + EnterCriticalSection(&csMemFilesLock); + AUTO_VAR(it, m_MEM_Files.find(wName)); + if(it != m_MEM_Files.end()) + { + PMEMDATA pData = (*it).second; + *ppbData=pData->pbData; + *pdwBytes=pData->dwBytes; + } + LeaveCriticalSection(&csMemFilesLock); +} + +void CMinecraftApp::AddMemoryTPDFile(int iConfig,PBYTE pbData,DWORD dwBytes) +{ + EnterCriticalSection(&csMemTPDLock); + // check it's not already in + PMEMDATA pData=NULL; + AUTO_VAR(it, m_MEM_TPD.find(iConfig)); + if(it == m_MEM_TPD.end()) + { + pData = (PMEMDATA)new BYTE[sizeof(MEMDATA)]; + ZeroMemory( pData, sizeof(MEMDATA) ); + pData->pbData=pbData; + pData->dwBytes=dwBytes; + pData->ucRefCount = 1; + + m_MEM_TPD[iConfig]=pData; + } + + LeaveCriticalSection(&csMemTPDLock); +} + +void CMinecraftApp::RemoveMemoryTPDFile(int iConfig) +{ + EnterCriticalSection(&csMemTPDLock); + // check it's not already in + PMEMDATA pData=NULL; + AUTO_VAR(it, m_MEM_TPD.find(iConfig)); + if(it != m_MEM_TPD.end()) + { + pData=m_MEM_TPD[iConfig]; + delete [] pData; + m_MEM_TPD.erase(iConfig); + } + + LeaveCriticalSection(&csMemTPDLock); +} + +#ifdef _XBOX +int CMinecraftApp::GetTPConfigVal(WCHAR *pwchDataFile) +{ + DLC_INFO *pDLCInfo=NULL; + // run through the DLC info to find the right texture pack/mash-up pack + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + ULONGLONG ull=app.GetDLCInfoTexturesFullOffer(i); + pDLCInfo=app.GetDLCInfoForFullOfferID(ull); + + if(wcscmp(pwchDataFile,pDLCInfo->wchDataFile)==0) + { + return pDLCInfo->iConfig; + } + } + + return -1; +} +#elif defined _XBOX_ONE +int CMinecraftApp::GetTPConfigVal(WCHAR *pwchDataFile) +{ + DLC_INFO *pDLCInfo=NULL; + // run through the DLC info to find the right texture pack/mash-up pack + for(unsigned int i = 0; i < app.GetDLCInfoTexturesOffersCount(); ++i) + { + pDLCInfo=app.GetDLCInfoForFullOfferID((WCHAR *)app.GetDLCInfoTexturesFullOffer(i).c_str()); + + if(wcscmp(pwchDataFile,pDLCInfo->wchDataFile)==0) + { + return pDLCInfo->iConfig; + } + } + + return -1; +} +#elif defined _WINDOWS64 +int CMinecraftApp::GetTPConfigVal(WCHAR *pwchDataFile) +{ + return -1; +} +#endif +bool CMinecraftApp::IsFileInTPD(int iConfig) +{ + bool val = false; + + EnterCriticalSection(&csMemTPDLock); + AUTO_VAR(it, m_MEM_TPD.find(iConfig)); + if(it != m_MEM_TPD.end()) val = true; + LeaveCriticalSection(&csMemTPDLock); + + return val; +} + +void CMinecraftApp::GetTPD(int iConfig,PBYTE *ppbData,DWORD *pdwBytes) +{ + EnterCriticalSection(&csMemTPDLock); + AUTO_VAR(it, m_MEM_TPD.find(iConfig)); + if(it != m_MEM_TPD.end()) + { + PMEMDATA pData = (*it).second; + *ppbData=pData->pbData; + *pdwBytes=pData->dwBytes; + } + LeaveCriticalSection(&csMemTPDLock); +} + + +// bool CMinecraftApp::UploadFileToGlobalStorage(int iQuadrant, C4JStorage::eGlobalStorage eStorageFacility, wstring *wsFile ) +// { +// bool bRes=false; +// #ifndef _CONTENT_PACKAGE +// // read the local file +// File gtsFile( wsFile->c_str() ); +// +// __int64 fileSize = gtsFile.length(); +// +// if(fileSize!=0) +// { +// FileInputStream fis(gtsFile); +// byteArray ba((int)fileSize); +// fis.read(ba); +// fis.close(); +// +// bRes=StorageManager.WriteTMSFile(iQuadrant,eStorageFacility,(WCHAR *)wsFile->c_str(),ba.data, ba.length); +// +// } +// #endif +// return bRes; +// } + + + + + + +void CMinecraftApp::StoreLaunchData() +{ + +} + +void CMinecraftApp::ExitGame() +{ +} + +// Invites + +void CMinecraftApp::ProcessInvite(DWORD dwUserIndex, DWORD dwLocalUsersMask, const INVITE_INFO * pInviteInfo) +{ + m_InviteData.dwUserIndex=dwUserIndex; + m_InviteData.dwLocalUsersMask=dwLocalUsersMask; + m_InviteData.pInviteInfo=pInviteInfo; + //memcpy(&m_InviteData,pJoinData,sizeof(JoinFromInviteData)); + SetAction(dwUserIndex,eAppAction_ExitAndJoinFromInvite); +} + +int CMinecraftApp::ExitAndJoinFromInvite(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CMinecraftApp* pApp = (CMinecraftApp*)pParam; + //Minecraft *pMinecraft=Minecraft::GetInstance(); + + // buttons are swapped on this menu + if(result==C4JStorage::EMessage_ResultDecline) + { + pApp->SetAction(iPad,eAppAction_ExitAndJoinFromInviteConfirmed); + } + + return 0; +} + +int CMinecraftApp::ExitAndJoinFromInviteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + CMinecraftApp *pClass = (CMinecraftApp *)pParam; + // Exit with or without saving + // Decline means save in this dialog + if(result==C4JStorage::EMessage_ResultDecline || result==C4JStorage::EMessage_ResultThirdOption) + { + if( result==C4JStorage::EMessage_ResultDecline ) // Save + { + // Check they have the full texture pack if they are using one + // 4J-PB - Is the player trying to save but they are using a trial texturepack ? + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + + DLCPack * pDLCPack=tPack->getDLCPack(); + if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + // upsell + // get the dlc texture pack + +#ifdef _XBOX + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullOfferID_Full); + + // tell sentient about the upsell of the full version of the skin pack + TelemetryManager->RecordUpsellPresented(iPad, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); +#endif + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + // Give the player a warning about the trial version of the texture pack + ui.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, iPad,&CMinecraftApp::WarningTrialTexturePackReturned,pClass,app.GetStringTable()); + + return S_OK; + } + } +#ifndef _XBOX_ONE + // does the save exist? + bool bSaveExists; + StorageManager.DoesSaveExist(&bSaveExists); + // 4J-PB - we check if the save exists inside the libs + // we need to ask if they are sure they want to overwrite the existing game + if(bSaveExists) + { + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_TITLE_SAVE_GAME, IDS_CONFIRM_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::ExitAndJoinFromInviteAndSaveReturned,pClass, app.GetStringTable()); + return 0; + } + else +#endif + { +#if defined(_XBOX_ONE) || defined(__ORBIS__) + StorageManager.SetSaveDisabled(false); +#endif + MinecraftServer::getInstance()->setSaveOnExit( true ); + } + } + else + { + // been a few requests for a confirm on exit without saving + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + ui.RequestMessageBox(IDS_TITLE_DECLINE_SAVE_GAME, IDS_CONFIRM_DECLINE_SAVE_GAME, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CMinecraftApp::ExitAndJoinFromInviteDeclineSaveReturned,pClass, app.GetStringTable()); + return 0; + } + + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitAndJoinFromInviteConfirmed); + } + return 0; +} + +int CMinecraftApp::WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ +#ifdef _XBOX + + CMinecraftApp* pClass = (CMinecraftApp*)pParam; + + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + // get the dlc texture pack + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + ULONGLONG ullIndexA[1]; + + // Need to get the parent packs id, since this may be one of many child packs with their own ids + app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullIndexA[0]); + + if(result==C4JStorage::EMessage_ResultAccept) + { + if(ProfileManager.IsSignedIn(iPad)) + { + // need to allow downloads here, or the player would need to quit the game to let the download of a texture pack happen. This might affect the network traffic, since the download could take all the bandwidth... + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + else + { + TelemetryManager->RecordUpsellResponded(iPad, eSet_UpsellID_Texture_DLC, ( ullIndexA[0] & 0xFFFFFFFF ), eSen_UpsellOutcome_Declined); + } +#endif + return 0; +} + +int CMinecraftApp::ExitAndJoinFromInviteAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + //CMinecraftApp* pClass = (CMinecraftApp*)pParam; + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + INT saveOrCheckpointId = 0; + + // Check they have the full texture pack if they are using one + // 4J-PB - Is the player trying to save but they are using a trial texturepack ? + if(!Minecraft::GetInstance()->skins->isUsingDefaultSkin()) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + + DLCPack * pDLCPack=tPack->getDLCPack(); + if(!pDLCPack->hasPurchasedFile( DLCManager::e_DLCType_Texture, L"" )) + { + // upsell + // get the dlc texture pack + +#ifdef _XBOX + DLCTexturePack *pDLCTexPack=(DLCTexturePack *)tPack; + ULONGLONG ullOfferID_Full; + app.GetDLCFullOfferIDForPackID(pDLCTexPack->getDLCParentPackId(),&ullOfferID_Full); + + // tell sentient about the upsell of the full version of the skin pack + TelemetryManager->RecordUpsellPresented(iPad, eSet_UpsellID_Texture_DLC, ullOfferID_Full & 0xFFFFFFFF); +#endif + + UINT uiIDA[2]; + uiIDA[0]=IDS_CONFIRM_OK; + uiIDA[1]=IDS_CONFIRM_CANCEL; + + // Give the player a warning about the trial version of the texture pack + ui.RequestMessageBox(IDS_WARNING_DLC_TRIALTEXTUREPACK_TITLE, IDS_WARNING_DLC_TRIALTEXTUREPACK_TEXT, uiIDA, 2, iPad,&CMinecraftApp::WarningTrialTexturePackReturned,NULL,app.GetStringTable()); + + return S_OK; + } + } + //bool validSave = StorageManager.GetSaveUniqueNumber(&saveOrCheckpointId); + //SentientManager.RecordLevelSaveOrCheckpoint(ProfileManager.GetPrimaryPad(), saveOrCheckpointId); + MinecraftServer::getInstance()->setSaveOnExit( true ); + // flag a app action of exit and join game from invite + app.SetAction(iPad,eAppAction_ExitAndJoinFromInviteConfirmed); + } + return 0; +} + +int CMinecraftApp::ExitAndJoinFromInviteDeclineSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { +#if defined(_XBOX_ONE) || defined(__ORBIS__) + StorageManager.SetSaveDisabled(false); +#endif + MinecraftServer::getInstance()->setSaveOnExit( false ); + // flag a app action of exit and join game from invite + app.SetAction(iPad,eAppAction_ExitAndJoinFromInviteConfirmed); + } + return 0; +} + +////////////////////////////////////////////////////////////////////////// +// +// FatalLoadError +// +// This is called when we can't load one of the required files at startup +// It tends to mean the files have been corrupted. +// We have to assume that we've not been able to load the text for the game. +// +////////////////////////////////////////////////////////////////////////// +void CMinecraftApp::FatalLoadError() +{ + +} + +TIPSTRUCT CMinecraftApp::m_GameTipA[MAX_TIPS_GAMETIP]= +{ + { 0, IDS_TIPS_GAMETIP_1}, + { 0, IDS_TIPS_GAMETIP_2}, + { 0, IDS_TIPS_GAMETIP_3}, + { 0, IDS_TIPS_GAMETIP_4}, + { 0, IDS_TIPS_GAMETIP_5}, + { 0, IDS_TIPS_GAMETIP_6}, + { 0, IDS_TIPS_GAMETIP_7}, + { 0, IDS_TIPS_GAMETIP_8}, + { 0, IDS_TIPS_GAMETIP_9}, + { 0, IDS_TIPS_GAMETIP_10}, + { 0, IDS_TIPS_GAMETIP_11}, + { 0, IDS_TIPS_GAMETIP_12}, + { 0, IDS_TIPS_GAMETIP_13}, + { 0, IDS_TIPS_GAMETIP_14}, + { 0, IDS_TIPS_GAMETIP_15}, + { 0, IDS_TIPS_GAMETIP_16}, + { 0, IDS_TIPS_GAMETIP_17}, + { 0, IDS_TIPS_GAMETIP_18}, + { 0, IDS_TIPS_GAMETIP_19}, + { 0, IDS_TIPS_GAMETIP_20}, + { 0, IDS_TIPS_GAMETIP_21}, + { 0, IDS_TIPS_GAMETIP_22}, + { 0, IDS_TIPS_GAMETIP_23}, + { 0, IDS_TIPS_GAMETIP_24}, + { 0, IDS_TIPS_GAMETIP_25}, + { 0, IDS_TIPS_GAMETIP_26}, + { 0, IDS_TIPS_GAMETIP_27}, + { 0, IDS_TIPS_GAMETIP_28}, + { 0, IDS_TIPS_GAMETIP_29}, + { 0, IDS_TIPS_GAMETIP_30}, + { 0, IDS_TIPS_GAMETIP_31}, + { 0, IDS_TIPS_GAMETIP_32}, + { 0, IDS_TIPS_GAMETIP_33}, + { 0, IDS_TIPS_GAMETIP_34}, + { 0, IDS_TIPS_GAMETIP_35}, + { 0, IDS_TIPS_GAMETIP_36}, + { 0, IDS_TIPS_GAMETIP_37}, + { 0, IDS_TIPS_GAMETIP_38}, + { 0, IDS_TIPS_GAMETIP_39}, + { 0, IDS_TIPS_GAMETIP_40}, + { 0, IDS_TIPS_GAMETIP_41}, + { 0, IDS_TIPS_GAMETIP_42}, + { 0, IDS_TIPS_GAMETIP_43}, + { 0, IDS_TIPS_GAMETIP_44}, + { 0, IDS_TIPS_GAMETIP_45}, + { 0, IDS_TIPS_GAMETIP_46}, + { 0, IDS_TIPS_GAMETIP_47}, + { 0, IDS_TIPS_GAMETIP_48}, + { 0, IDS_TIPS_GAMETIP_49}, + { 0, IDS_TIPS_GAMETIP_50}, +}; + +TIPSTRUCT CMinecraftApp::m_TriviaTipA[MAX_TIPS_TRIVIATIP]= +{ + { 0, IDS_TIPS_TRIVIA_1}, + { 0, IDS_TIPS_TRIVIA_2}, + { 0, IDS_TIPS_TRIVIA_3}, + { 0, IDS_TIPS_TRIVIA_4}, + { 0, IDS_TIPS_TRIVIA_5}, + { 0, IDS_TIPS_TRIVIA_6}, + { 0, IDS_TIPS_TRIVIA_7}, + { 0, IDS_TIPS_TRIVIA_8}, + { 0, IDS_TIPS_TRIVIA_9}, + { 0, IDS_TIPS_TRIVIA_10}, + { 0, IDS_TIPS_TRIVIA_11}, + { 0, IDS_TIPS_TRIVIA_12}, + { 0, IDS_TIPS_TRIVIA_13}, + { 0, IDS_TIPS_TRIVIA_14}, + { 0, IDS_TIPS_TRIVIA_15}, + { 0, IDS_TIPS_TRIVIA_16}, + { 0, IDS_TIPS_TRIVIA_17}, + { 0, IDS_TIPS_TRIVIA_18}, + { 0, IDS_TIPS_TRIVIA_19}, + { 0, IDS_TIPS_TRIVIA_20}, +}; + +Random *CMinecraftApp::TipRandom = new Random(); + +int CMinecraftApp::TipsSortFunction(const void* a, const void* b) +{ + return ((TIPSTRUCT*)a)->iSortValue - ((TIPSTRUCT*)b)->iSortValue; +} + +void CMinecraftApp::InitialiseTips() +{ + // We'll randomise the tips at start up based on their priority + + ZeroMemory(m_TipIDA,sizeof(UINT)*MAX_TIPS_GAMETIP+MAX_TIPS_TRIVIATIP); + + // Make the first tip tell you that you can play splitscreen in HD modes if you are in SD + if(!RenderManager.IsHiDef()) + { + m_GameTipA[0].uiStringID=IDS_TIPS_GAMETIP_0; + } + // randomise then quicksort + // going to leave the multiplayer tip so it is always first + +// Only randomise the content package build +#ifdef _CONTENT_PACKAGE + + for(int i=1;inextInt(); + } + qsort( &m_GameTipA[1], MAX_TIPS_GAMETIP-1, sizeof(TIPSTRUCT), TipsSortFunction ); +#endif + + for(int i=0;inextInt(); + } + qsort( m_TriviaTipA, MAX_TIPS_TRIVIATIP, sizeof(TIPSTRUCT), TipsSortFunction ); + + + int iCurrentGameTip=0; + int iCurrentTriviaTip=0; + + for(int i=0;iskins->getSelected()->getColourTable()->getColour(colour); +} + +int CMinecraftApp::GetHTMLFontSize(EHTMLFontSize size) +{ + return s_iHTMLFontSizesA[size]; +} + +wstring CMinecraftApp::FormatHTMLString(int iPad, const wstring &desc, int shadowColour /*= 0xFFFFFFFF*/) +{ + wstring text(desc); + + wchar_t replacements[64]; + // We will also insert line breaks here as couldn't figure out how to get them to come through from strings.resx ! + text = replaceAll(text, L"{*B*}", L"
" ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_T1)); + text = replaceAll(text, L"{*T1*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_T2)); + text = replaceAll(text, L"{*T2*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_T3)); + text = replaceAll(text, L"{*T3*}", replacements ); // for How To Play + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_Black)); + text = replaceAll(text, L"{*ETB*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_White)); + text = replaceAll(text, L"{*ETW*}", replacements ); + text = replaceAll(text, L"{*EF*}", L"" ); + + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_0), shadowColour); + text = replaceAll(text, L"{*C0*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_1), shadowColour); + text = replaceAll(text, L"{*C1*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_2), shadowColour); + text = replaceAll(text, L"{*C2*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_3), shadowColour); + text = replaceAll(text, L"{*C3*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_4), shadowColour); + text = replaceAll(text, L"{*C4*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_5), shadowColour); + text = replaceAll(text, L"{*C5*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_6), shadowColour); + text = replaceAll(text, L"{*C6*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_7), shadowColour); + text = replaceAll(text, L"{*C7*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_8), shadowColour); + text = replaceAll(text, L"{*C8*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_9), shadowColour); + text = replaceAll(text, L"{*C9*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_a), shadowColour); + text = replaceAll(text, L"{*CA*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_b), shadowColour); + text = replaceAll(text, L"{*CB*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_c), shadowColour); + text = replaceAll(text, L"{*CC*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_d), shadowColour); + text = replaceAll(text, L"{*CD*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_e), shadowColour); + text = replaceAll(text, L"{*CE*}", replacements ); + swprintf(replacements,64,L"", GetHTMLColour(eHTMLColor_f), shadowColour); + text = replaceAll(text, L"{*CF*}", replacements ); + + // Swap for southpaw. + if ( app.GetGameSettings(iPad,eGameSetting_ControlSouthPaw) ) + { + text = replaceAll(text, L"{*CONTROLLER_ACTION_MOVE*}", GetActionReplacement(iPad,MINECRAFT_ACTION_LOOK_RIGHT ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_LOOK*}", GetActionReplacement(iPad,MINECRAFT_ACTION_RIGHT ) ); + + text = replaceAll(text, L"{*CONTROLLER_MENU_NAVIGATE*}", GetVKReplacement(VK_PAD_RTHUMB_LEFT) ); + } + else // Normal right handed. + { + text = replaceAll(text, L"{*CONTROLLER_ACTION_MOVE*}", GetActionReplacement(iPad,MINECRAFT_ACTION_RIGHT ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_LOOK*}", GetActionReplacement(iPad,MINECRAFT_ACTION_LOOK_RIGHT ) ); + + text = replaceAll(text, L"{*CONTROLLER_MENU_NAVIGATE*}", GetVKReplacement(VK_PAD_LTHUMB_LEFT) ); + } + + text = replaceAll(text, L"{*CONTROLLER_ACTION_JUMP*}", GetActionReplacement(iPad,MINECRAFT_ACTION_JUMP ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_SNEAK*}", GetActionReplacement(iPad,MINECRAFT_ACTION_SNEAK_TOGGLE ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_USE*}", GetActionReplacement(iPad,MINECRAFT_ACTION_USE ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_ACTION*}", GetActionReplacement(iPad,MINECRAFT_ACTION_ACTION ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_LEFT_SCROLL*}", GetActionReplacement(iPad,MINECRAFT_ACTION_LEFT_SCROLL ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_RIGHT_SCROLL*}", GetActionReplacement(iPad,MINECRAFT_ACTION_RIGHT_SCROLL ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_INVENTORY*}", GetActionReplacement(iPad,MINECRAFT_ACTION_INVENTORY ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_CRAFTING*}", GetActionReplacement(iPad,MINECRAFT_ACTION_CRAFTING ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_DROP*}", GetActionReplacement(iPad,MINECRAFT_ACTION_DROP ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_CAMERA*}", GetActionReplacement(iPad,MINECRAFT_ACTION_RENDER_THIRD_PERSON ) ); + text = replaceAll(text, L"{*CONTROLLER_VK_A*}", GetVKReplacement(VK_PAD_A) ); + text = replaceAll(text, L"{*CONTROLLER_VK_B*}", GetVKReplacement(VK_PAD_B) ); + text = replaceAll(text, L"{*CONTROLLER_VK_X*}", GetVKReplacement(VK_PAD_X) ); + text = replaceAll(text, L"{*CONTROLLER_VK_Y*}", GetVKReplacement(VK_PAD_Y) ); + text = replaceAll(text, L"{*CONTROLLER_VK_LB*}", GetVKReplacement(VK_PAD_LSHOULDER) ); + text = replaceAll(text, L"{*CONTROLLER_VK_RB*}", GetVKReplacement(VK_PAD_RSHOULDER) ); + text = replaceAll(text, L"{*CONTROLLER_VK_LS*}", GetVKReplacement(VK_PAD_LTHUMB_UP) ); + text = replaceAll(text, L"{*CONTROLLER_VK_RS*}", GetVKReplacement(VK_PAD_RTHUMB_UP) ); + text = replaceAll(text, L"{*CONTROLLER_VK_LT*}", GetVKReplacement(VK_PAD_LTRIGGER) ); + text = replaceAll(text, L"{*CONTROLLER_VK_RT*}", GetVKReplacement(VK_PAD_RTRIGGER) ); + text = replaceAll(text, L"{*ICON_SHANK_01*}", GetIconReplacement(XZP_ICON_SHANK_01) ); + text = replaceAll(text, L"{*ICON_SHANK_03*}", GetIconReplacement(XZP_ICON_SHANK_03) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_UP*}", GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_UP ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_DOWN*}", GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_DOWN ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_RIGHT*}", GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_RIGHT ) ); + text = replaceAll(text, L"{*CONTROLLER_ACTION_DPAD_LEFT*}", GetActionReplacement(iPad,MINECRAFT_ACTION_DPAD_LEFT ) ); +#if defined _XBOX_ONE || defined __PSVITA__ + text = replaceAll(text, L"{*CONTROLLER_VK_START*}", GetVKReplacement(VK_PAD_START ) ); + text = replaceAll(text, L"{*CONTROLLER_VK_BACK*}", GetVKReplacement(VK_PAD_BACK ) ); +#endif + +#ifdef _XBOX + wstring imageRoot = L""; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + imageRoot = pMinecraft->skins->getSelected()->getXuiRootPath(); + + text = replaceAll(text, L"{*IMAGEROOT*}", imageRoot); +#endif // _XBOX + + // Fix for #8903 - UI: Localization: KOR/JPN/CHT: Button Icons are rendered with padding space, which looks no good + DWORD dwLanguage = XGetLanguage( ); + switch(dwLanguage) + { + case XC_LANGUAGE_KOREAN: + case XC_LANGUAGE_JAPANESE: + case XC_LANGUAGE_TCHINESE: + text = replaceAll(text, L" ", L"" ); + break; + } + + return text; +} + +wstring CMinecraftApp::GetActionReplacement(int iPad, unsigned char ucAction) +{ + unsigned int input = InputManager.GetGameJoypadMaps(InputManager.GetJoypadMapVal(iPad) ,ucAction); + +#ifdef _XBOX + switch(input) + { + case _360_JOY_BUTTON_A: + return app.GetString( IDS_CONTROLLER_A ); + case _360_JOY_BUTTON_B: + return app.GetString( IDS_CONTROLLER_B ); + case _360_JOY_BUTTON_X: + return app.GetString( IDS_CONTROLLER_X ); + case _360_JOY_BUTTON_Y: + return app.GetString( IDS_CONTROLLER_Y ); + case _360_JOY_BUTTON_LSTICK_UP: + case _360_JOY_BUTTON_LSTICK_DOWN: + case _360_JOY_BUTTON_LSTICK_LEFT: + case _360_JOY_BUTTON_LSTICK_RIGHT: + return app.GetString( IDS_CONTROLLER_LEFT_STICK ); + case _360_JOY_BUTTON_RSTICK_LEFT: + case _360_JOY_BUTTON_RSTICK_RIGHT: + case _360_JOY_BUTTON_RSTICK_UP: + case _360_JOY_BUTTON_RSTICK_DOWN: + return app.GetString( IDS_CONTROLLER_RIGHT_STICK ); + case _360_JOY_BUTTON_LT: + return app.GetString( IDS_CONTROLLER_LEFT_TRIGGER ); + case _360_JOY_BUTTON_RT: + return app.GetString( IDS_CONTROLLER_RIGHT_TRIGGER ); + case _360_JOY_BUTTON_RB: + return app.GetString( IDS_CONTROLLER_RIGHT_BUMPER ); + case _360_JOY_BUTTON_LB: + return app.GetString( IDS_CONTROLLER_LEFT_BUMPER ); + case _360_JOY_BUTTON_BACK: + return app.GetString( IDS_CONTROLLER_BACK ); + case _360_JOY_BUTTON_START: + return app.GetString( IDS_CONTROLLER_START ); + case _360_JOY_BUTTON_RTHUMB: + return app.GetString( IDS_CONTROLLER_RIGHT_THUMBSTICK ); + case _360_JOY_BUTTON_LTHUMB: + return app.GetString( IDS_CONTROLLER_LEFT_THUMBSTICK ); + case _360_JOY_BUTTON_DPAD_LEFT: + return app.GetString( IDS_CONTROLLER_DPAD_L ); + case _360_JOY_BUTTON_DPAD_RIGHT: + return app.GetString( IDS_CONTROLLER_DPAD_R ); + case _360_JOY_BUTTON_DPAD_UP: + return app.GetString( IDS_CONTROLLER_DPAD_U ); + case _360_JOY_BUTTON_DPAD_DOWN: + return app.GetString( IDS_CONTROLLER_DPAD_D ); + }; + return L""; +#else + wstring replacement = L""; + + // 4J Stu - Some of our actions can be mapped to multiple physical buttons, so replaces the switch that was here + if (input & _360_JOY_BUTTON_A) replacement = L"ButtonA"; + else if(input &_360_JOY_BUTTON_B) replacement = L"ButtonB"; + else if(input &_360_JOY_BUTTON_X) replacement = L"ButtonX"; + else if(input &_360_JOY_BUTTON_Y) replacement = L"ButtonY"; + else if( + (input &_360_JOY_BUTTON_LSTICK_UP) || + (input &_360_JOY_BUTTON_LSTICK_DOWN) || + (input &_360_JOY_BUTTON_LSTICK_LEFT) || + (input &_360_JOY_BUTTON_LSTICK_RIGHT) + ) + { + replacement = L"ButtonLeftStick"; + } + else if( + (input &_360_JOY_BUTTON_RSTICK_LEFT) || + (input &_360_JOY_BUTTON_RSTICK_RIGHT) || + (input &_360_JOY_BUTTON_RSTICK_UP) || + (input &_360_JOY_BUTTON_RSTICK_DOWN) + ) + { + replacement = L"ButtonRightStick"; + } + else if(input &_360_JOY_BUTTON_DPAD_LEFT) replacement = L"ButtonDpadL"; + else if(input &_360_JOY_BUTTON_DPAD_RIGHT) replacement = L"ButtonDpadR"; + else if(input &_360_JOY_BUTTON_DPAD_UP) replacement = L"ButtonDpadU"; + else if(input &_360_JOY_BUTTON_DPAD_DOWN) replacement = L"ButtonDpadD"; + else if(input &_360_JOY_BUTTON_LT) replacement = L"ButtonLeftTrigger"; + else if(input &_360_JOY_BUTTON_RT) replacement = L"ButtonRightTrigger"; + else if(input &_360_JOY_BUTTON_RB) replacement = L"ButtonRightBumper"; + else if(input &_360_JOY_BUTTON_LB) replacement = L"ButtonLeftBumper"; + else if(input &_360_JOY_BUTTON_BACK) replacement = L"ButtonBack"; + else if(input &_360_JOY_BUTTON_START) replacement = L"ButtonStart"; + else if(input &_360_JOY_BUTTON_RTHUMB) replacement = L"ButtonRS"; + else if(input &_360_JOY_BUTTON_LTHUMB) replacement = L"ButtonLS"; + + wchar_t string[128]; + +#ifdef __PS3__ + int size = 30; +#elif defined _WIN64 + int size = 45; + if(ui.getScreenWidth() < 1920) size = 30; +#else + int size = 45; +#endif + + swprintf(string,128,L"", replacement.c_str(), size, size); + + return string; +#endif +} + +wstring CMinecraftApp::GetVKReplacement(unsigned int uiVKey) +{ +#ifdef _XBOX + switch(uiVKey) + { + case VK_PAD_A: + return app.GetString( IDS_CONTROLLER_A ); + case VK_PAD_B: + return app.GetString( IDS_CONTROLLER_B ); + case VK_PAD_X: + return app.GetString( IDS_CONTROLLER_X ); + case VK_PAD_Y: + return app.GetString( IDS_CONTROLLER_Y ); + case VK_PAD_LSHOULDER: + return app.GetString( IDS_CONTROLLER_LEFT_BUMPER ); + case VK_PAD_RSHOULDER: + return app.GetString( IDS_CONTROLLER_RIGHT_BUMPER ); + case VK_PAD_LTRIGGER: + return app.GetString( IDS_CONTROLLER_LEFT_TRIGGER ); + case VK_PAD_RTRIGGER: + return app.GetString( IDS_CONTROLLER_RIGHT_TRIGGER ); + case VK_PAD_LTHUMB_UP : + case VK_PAD_LTHUMB_DOWN : + case VK_PAD_LTHUMB_RIGHT : + case VK_PAD_LTHUMB_LEFT : + case VK_PAD_LTHUMB_UPLEFT : + case VK_PAD_LTHUMB_UPRIGHT : + case VK_PAD_LTHUMB_DOWNRIGHT: + case VK_PAD_LTHUMB_DOWNLEFT : + return app.GetString( IDS_CONTROLLER_LEFT_STICK ); + case VK_PAD_RTHUMB_UP : + case VK_PAD_RTHUMB_DOWN : + case VK_PAD_RTHUMB_RIGHT : + case VK_PAD_RTHUMB_LEFT : + case VK_PAD_RTHUMB_UPLEFT : + case VK_PAD_RTHUMB_UPRIGHT : + case VK_PAD_RTHUMB_DOWNRIGHT: + case VK_PAD_RTHUMB_DOWNLEFT : + return app.GetString( IDS_CONTROLLER_RIGHT_STICK ); + default: + break; + } + return NULL; +#else + wstring replacement = L""; + switch(uiVKey) + { + case VK_PAD_A: +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) + if( InputManager.IsCircleCrossSwapped() ) replacement = L"ButtonB"; + else replacement = L"ButtonA"; +#else + replacement = L"ButtonA"; +#endif + break; + case VK_PAD_B: +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) + if( InputManager.IsCircleCrossSwapped() ) replacement = L"ButtonA"; + else replacement = L"ButtonB"; +#else + replacement = L"ButtonB"; +#endif + break; + case VK_PAD_X: + replacement = L"ButtonX"; + break; + case VK_PAD_Y: + replacement = L"ButtonY"; + break; + case VK_PAD_LSHOULDER: + replacement = L"ButtonLeftBumper"; + break; + case VK_PAD_RSHOULDER: + replacement = L"ButtonRightBumper"; + break; + case VK_PAD_LTRIGGER: + replacement = L"ButtonLeftTrigger"; + break; + case VK_PAD_RTRIGGER: + replacement = L"ButtonRightTrigger"; + break; + case VK_PAD_LTHUMB_UP : + case VK_PAD_LTHUMB_DOWN : + case VK_PAD_LTHUMB_RIGHT : + case VK_PAD_LTHUMB_LEFT : + case VK_PAD_LTHUMB_UPLEFT : + case VK_PAD_LTHUMB_UPRIGHT : + case VK_PAD_LTHUMB_DOWNRIGHT: + case VK_PAD_LTHUMB_DOWNLEFT : + replacement = L"ButtonLeftStick"; + break; + case VK_PAD_RTHUMB_UP : + case VK_PAD_RTHUMB_DOWN : + case VK_PAD_RTHUMB_RIGHT : + case VK_PAD_RTHUMB_LEFT : + case VK_PAD_RTHUMB_UPLEFT : + case VK_PAD_RTHUMB_UPRIGHT : + case VK_PAD_RTHUMB_DOWNRIGHT: + case VK_PAD_RTHUMB_DOWNLEFT : + replacement = L"ButtonRightStick"; + break; +#if defined _XBOX_ONE || defined __PSVITA__ + case VK_PAD_START: + replacement = L"ButtonStart"; + break; + case VK_PAD_BACK: + replacement = L"ButtonBack"; + break; +#endif + default: + break; + } + wchar_t string[128]; + +#ifdef __PS3__ + int size = 30; +#elif defined _WIN64 + int size = 45; + if(ui.getScreenWidth() < 1920) size = 30; +#else + int size = 45; +#endif + + swprintf(string,128,L"", replacement.c_str(), size, size); + + return string; +#endif +} + +wstring CMinecraftApp::GetIconReplacement(unsigned int uiIcon) +{ +#ifdef _XBOX + switch(uiIcon) + { + case XZP_ICON_SHANK_01: + return app.GetString( IDS_ICON_SHANK_01 ); + case XZP_ICON_SHANK_03: + return app.GetString( IDS_ICON_SHANK_03 ); + default: + break; + } + return NULL; +#else + wchar_t string[128]; + +#ifdef __PS3__ + int size = 22; +#elif defined _WIN64 + int size = 33; + if(ui.getScreenWidth() < 1920) size = 22; +#else + int size = 33; +#endif + + swprintf(string,128,L"", size, size); + wstring result = L""; + switch(uiIcon) + { + case XZP_ICON_SHANK_01: + result = string; + break; + case XZP_ICON_SHANK_03: + result.append(string).append(string).append(string); + break; + default: + break; + } + return result; +#endif +} + +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +unordered_map CMinecraftApp::MojangData; +unordered_map CMinecraftApp::DLCTextures_PackID; +unordered_map CMinecraftApp::DLCInfo; +unordered_map CMinecraftApp::DLCInfo_SkinName; +#elif defined(_DURANGO) +unordered_map CMinecraftApp::MojangData; +unordered_map CMinecraftApp::DLCTextures_PackID; // for mash-up packs & texture packs +//unordered_map CMinecraftApp::DLCInfo_Trial; // full offerid, dlc_info +unordered_map CMinecraftApp::DLCInfo_Full; // full offerid, dlc_info +unordered_map CMinecraftApp::DLCInfo_SkinName; // skin name, full offer id +#else +unordered_map CMinecraftApp::MojangData; +unordered_map CMinecraftApp::DLCTextures_PackID; +unordered_map CMinecraftApp::DLCInfo_Trial; +unordered_map CMinecraftApp::DLCInfo_Full; +unordered_map CMinecraftApp::DLCInfo_SkinName; +#endif + + + +HRESULT CMinecraftApp::RegisterMojangData(WCHAR *pXuidName, PlayerUID xuid, WCHAR *pSkin, WCHAR *pCape) +{ + HRESULT hr=S_OK; + eXUID eTempXuid=eXUID_Undefined; + MOJANG_DATA *pMojangData=NULL; + + // ignore the names if we don't recognize them + if(pXuidName!=NULL) + { + if( wcscmp( pXuidName, L"XUID_NOTCH" ) == 0 ) + { + eTempXuid = eXUID_Notch; // might be needed for the apple at some point + } + else if( wcscmp( pXuidName, L"XUID_DEADMAU5" ) == 0 ) + { + eTempXuid = eXUID_Deadmau5; // Needed for the deadmau5 ears + } + else + { + eTempXuid=eXUID_NoName; + } + } + + if(eTempXuid!=eXUID_Undefined) + { + pMojangData = new MOJANG_DATA; + ZeroMemory(pMojangData,sizeof(MOJANG_DATA)); + pMojangData->eXuid=eTempXuid; + + wcsncpy( pMojangData->wchSkin, pSkin, MAX_CAPENAME_SIZE); + wcsncpy( pMojangData->wchCape, pCape, MAX_CAPENAME_SIZE); + MojangData[xuid]=pMojangData; + } + + return hr; +} + +MOJANG_DATA *CMinecraftApp::GetMojangDataForXuid(PlayerUID xuid) +{ + return MojangData[xuid]; +} + +HRESULT CMinecraftApp::RegisterConfigValues(WCHAR *pType, int iValue) +{ + HRESULT hr=S_OK; + +// #ifdef _XBOX +// if(pType!=NULL) +// { +// if(wcscmp(pType,L"XboxOneTransfer")==0) +// { +// if(iValue>0) +// { +// app.m_bTransferSavesToXboxOne=true; +// } +// else +// { +// app.m_bTransferSavesToXboxOne=false; +// } +// } +// else if(wcscmp(pType,L"TransferSlotCount")==0) +// { +// app.m_uiTransferSlotC=iValue; +// } +// +// } +// #endif + + + return hr; +} + +#if (defined _XBOX || defined _WINDOWS64) +HRESULT CMinecraftApp::RegisterDLCData(WCHAR *pType, WCHAR *pBannerName, int iGender, __uint64 ullOfferID_Full, __uint64 ullOfferID_Trial, WCHAR *pFirstSkin, unsigned int uiSortIndex, int iConfig, WCHAR *pDataFile) +{ + HRESULT hr=S_OK; + DLC_INFO *pDLCData=new DLC_INFO; + ZeroMemory(pDLCData,sizeof(DLC_INFO)); + pDLCData->ullOfferID_Full=ullOfferID_Full; + pDLCData->ullOfferID_Trial=ullOfferID_Trial; + pDLCData->eDLCType=e_DLC_NotDefined; + pDLCData->iGender=iGender; + pDLCData->uiSortIndex=uiSortIndex; + pDLCData->iConfig=iConfig; + +#ifndef __ORBIS__ + // ignore the names if we don't recognize them + if(pBannerName!=L"") + { + wcsncpy_s( pDLCData->wchBanner, pBannerName, MAX_BANNERNAME_SIZE); + } + + if(pDataFile[0]!=0) + { + wcsncpy_s( pDLCData->wchDataFile, pDataFile, MAX_BANNERNAME_SIZE); + } +#endif + + if(pType!=NULL) + { + if(wcscmp(pType,L"Skin")==0) + { + pDLCData->eDLCType=e_DLC_SkinPack; + } + else if(wcscmp(pType,L"Gamerpic")==0) + { + pDLCData->eDLCType=e_DLC_Gamerpics; + } + else if(wcscmp(pType,L"Theme")==0) + { + pDLCData->eDLCType=e_DLC_Themes; + } + else if(wcscmp(pType,L"Avatar")==0) + { + pDLCData->eDLCType=e_DLC_AvatarItems; + } + else if(wcscmp(pType,L"MashUpPack")==0) + { + pDLCData->eDLCType=e_DLC_MashupPacks; + DLCTextures_PackID[pDLCData->iConfig]=ullOfferID_Full; + } + else if(wcscmp(pType,L"TexturePack")==0) + { + pDLCData->eDLCType=e_DLC_TexturePacks; + DLCTextures_PackID[pDLCData->iConfig]=ullOfferID_Full; + } + + + } + + if(ullOfferID_Trial!=0ll) DLCInfo_Trial[ullOfferID_Trial]=pDLCData; + if(ullOfferID_Full!=0ll) DLCInfo_Full[ullOfferID_Full]=pDLCData; + if(pFirstSkin[0]!=0) DLCInfo_SkinName[pFirstSkin]=ullOfferID_Full; + + return hr; +} +#elif defined _XBOX_ONE + +unordered_map *CMinecraftApp::GetDLCInfo() +{ + return &DLCInfo_Full; +} + +HRESULT CMinecraftApp::RegisterDLCData(eDLCContentType eType, WCHAR *pwchBannerName,WCHAR *pwchProductId, WCHAR *pwchProductName, WCHAR *pwchFirstSkin, int iConfig, unsigned int uiSortIndex) +{ + HRESULT hr=S_OK; + // 4J-PB - need to convert the product id to uppercase because the catalog calls come back with upper case + WCHAR wchUppercaseProductID[64]; + if(pwchProductId[0]!=0) + { + for(int i=0;i<64;i++) + { + wchUppercaseProductID[i]=towupper((wchar_t)pwchProductId[i]); + } + } + + // check if we already have this info from the local DLC file + wstring wsTemp=wchUppercaseProductID; + + AUTO_VAR(it, DLCInfo_Full.find(wsTemp)); + if( it == DLCInfo_Full.end() ) + { + // Not found + + DLC_INFO *pDLCData=new DLC_INFO; + ZeroMemory(pDLCData,sizeof(DLC_INFO)); + + pDLCData->eDLCType=e_DLC_NotDefined; + pDLCData->uiSortIndex=uiSortIndex; + pDLCData->iConfig=iConfig; + + if(pwchProductId[0]!=0) + { + pDLCData->wsProductId=wchUppercaseProductID; + } + + // ignore the names if we don't recognize them + if(pwchBannerName!=L"") + { + wcsncpy_s( pDLCData->wchBanner, pwchBannerName, MAX_BANNERNAME_SIZE); + } + + if(pwchProductName[0]!=0) + { + pDLCData->wsDisplayName=pwchProductName; + } + + pDLCData->eDLCType=eType; + + switch(eType) + { + case e_DLC_MashupPacks: + case e_DLC_TexturePacks: + DLCTextures_PackID[iConfig]=pDLCData->wsProductId; + break; + } + + if(pwchFirstSkin[0]!=0) DLCInfo_SkinName[pwchFirstSkin]=pDLCData->wsProductId; + + #ifdef _XBOX_ONE + // ignore the names, and use the product id instead + DLCInfo_Full[pDLCData->wsProductId]=pDLCData; + #else + DLCInfo_Full[pDLCData->wsDisplayName]=pDLCData; + #endif + } + app.DebugPrintf("DLCInfo - type - %d, productID - %ls, name - %ls , banner - %ls, iconfig - %d, sort index - %d\n",eType,pwchProductId, pwchProductName,pwchBannerName, iConfig, uiSortIndex); + return hr; +} +#else + +HRESULT CMinecraftApp::RegisterDLCData(char *pchDLCName, unsigned int uiSortIndex,char *pchImageURL) +{ + // on PS3 we get all the required info from the name + char chDLCType[3]; + HRESULT hr=S_OK; + DLC_INFO *pDLCData=new DLC_INFO; + ZeroMemory(pDLCData,sizeof(DLC_INFO)); + + chDLCType[0]=pchDLCName[0]; + chDLCType[1]=pchDLCName[1]; + chDLCType[2]=0; + + pDLCData->iConfig = app.GetiConfigFromName(pchDLCName); + pDLCData->uiSortIndex=uiSortIndex; + pDLCData->eDLCType = app.GetDLCTypeFromName(pchDLCName); + strcpy(pDLCData->chImageURL,pchImageURL); + //bool bIsTrialDLC = app.GetTrialFromName(pchDLCName); + + switch(pDLCData->eDLCType) + { + case e_DLC_TexturePacks: + { + char *pchName=(char *)malloc(strlen(pchDLCName)+1); + strcpy(pchName,pchDLCName); + DLCTextures_PackID[pDLCData->iConfig]=pchName; + } + break; + case e_DLC_MashupPacks: + { + char *pchName=(char *)malloc(strlen(pchDLCName)+1); + strcpy(pchName,pchDLCName); + DLCTextures_PackID[pDLCData->iConfig]=pchName; + } + break; + default: + break; + } + + app.DebugPrintf(5,"Adding DLC - %s\n",pchDLCName); + DLCInfo[pchDLCName]=pDLCData; + +// if(ullOfferID_Trial!=0ll) DLCInfo_Trial[ullOfferID_Trial]=pDLCData; +// if(ullOfferID_Full!=0ll) DLCInfo_Full[ullOfferID_Full]=pDLCData; +// if(pFirstSkin[0]!=0) DLCInfo_SkinName[pFirstSkin]=ullOfferID_Full; + +// DLCInfo[ullOfferID_Trial]=pDLCData; + + return hr; +} +#endif + + + +#if defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__) +bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal) +{ + AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin)); + if( it == DLCInfo_SkinName.end() ) + { + return false; + } + else + { + *pullVal=(ULONGLONG)it->second; + return true; + } +} +bool CMinecraftApp::GetDLCNameForPackID(const int iPackID,char **ppchKeyID) +{ + AUTO_VAR(it, DLCTextures_PackID.find(iPackID)); + if( it == DLCTextures_PackID.end() ) + { + *ppchKeyID=NULL; + return false; + } + else + { + *ppchKeyID=(char *)it->second; + return true; + } +} +DLC_INFO *CMinecraftApp::GetDLCInfo(char *pchDLCName) +{ + string tempString=pchDLCName; + + if(DLCInfo.size()>0) + { + AUTO_VAR(it, DLCInfo.find(tempString)); + + if( it == DLCInfo.end() ) + { + // nothing for this + return NULL; + } + else + { + return it->second; + } + } + else return NULL; +} + +DLC_INFO *CMinecraftApp::GetDLCInfoFromTPackID(int iTPID) +{ + unordered_map::iterator it= DLCInfo.begin(); + + for(int i=0;isecond)->iConfig==iTPID) + { + return it->second; + } + ++it; + } + return NULL; +} + +DLC_INFO *CMinecraftApp::GetDLCInfo(int iIndex) +{ + unordered_map::iterator it= DLCInfo.begin(); + + for(int i=0;isecond; +} + +char *CMinecraftApp::GetDLCInfoTextures(int iIndex) +{ + unordered_map::iterator it= DLCTextures_PackID.begin(); + + for(int i=0;isecond; +} + +#elif defined _XBOX_ONE +bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,wstring &ProductId) +{ + AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin)); + if( it == DLCInfo_SkinName.end() ) + { + return false; + } + else + { + ProductId=it->second; + return true; + } +} +bool CMinecraftApp::GetDLCFullOfferIDForPackID(const int iPackID,wstring &ProductId) +{ + AUTO_VAR(it, DLCTextures_PackID.find(iPackID)); + if( it == DLCTextures_PackID.end() ) + { + return false; + } + else + { + ProductId=it->second; + return true; + } +} +// DLC_INFO *CMinecraftApp::GetDLCInfoForTrialOfferID(wstring &ProductId) +// { +// return NULL; +// } + +DLC_INFO *CMinecraftApp::GetDLCInfoTrialOffer(int iIndex) +{ + return NULL; +} +DLC_INFO *CMinecraftApp::GetDLCInfoFullOffer(int iIndex) +{ + unordered_map::iterator it= DLCInfo_Full.begin(); + + for(int i=0;isecond; +} +wstring CMinecraftApp::GetDLCInfoTexturesFullOffer(int iIndex) +{ + unordered_map::iterator it= DLCTextures_PackID.begin(); + + for(int i=0;isecond; +} +#else +bool CMinecraftApp::GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal) +{ + AUTO_VAR(it, DLCInfo_SkinName.find(FirstSkin)); + if( it == DLCInfo_SkinName.end() ) + { + return false; + } + else + { + *pullVal=(ULONGLONG)it->second; + return true; + } +} +bool CMinecraftApp::GetDLCFullOfferIDForPackID(const int iPackID,ULONGLONG *pullVal) +{ + AUTO_VAR(it, DLCTextures_PackID.find(iPackID)); + if( it == DLCTextures_PackID.end() ) + { + *pullVal=(ULONGLONG)0; + return false; + } + else + { + *pullVal=(ULONGLONG)it->second; + return true; + } +} +DLC_INFO *CMinecraftApp::GetDLCInfoForTrialOfferID(ULONGLONG ullOfferID_Trial) +{ + //DLC_INFO *pDLCInfo=NULL; + if(DLCInfo_Trial.size()>0) + { + AUTO_VAR(it, DLCInfo_Trial.find(ullOfferID_Trial)); + + if( it == DLCInfo_Trial.end() ) + { + // nothing for this + return NULL; + } + else + { + return it->second; + } + } + else return NULL; +} + +DLC_INFO *CMinecraftApp::GetDLCInfoTrialOffer(int iIndex) +{ + unordered_map::iterator it= DLCInfo_Trial.begin(); + + for(int i=0;isecond; +} +DLC_INFO *CMinecraftApp::GetDLCInfoFullOffer(int iIndex) +{ + unordered_map::iterator it= DLCInfo_Full.begin(); + + for(int i=0;isecond; +} +ULONGLONG CMinecraftApp::GetDLCInfoTexturesFullOffer(int iIndex) +{ + unordered_map::iterator it= DLCTextures_PackID.begin(); + + for(int i=0;isecond; +} +#endif + +#ifdef _XBOX_ONE + +DLC_INFO *CMinecraftApp::GetDLCInfoForFullOfferID(WCHAR *pwchProductID) +{ + wstring wsTemp = pwchProductID; + if(DLCInfo_Full.size()>0) + { + AUTO_VAR(it, DLCInfo_Full.find(wsTemp)); + + if( it == DLCInfo_Full.end() ) + { + // nothing for this + return NULL; + } + else + { + return it->second; + } + } + else return NULL; +} +DLC_INFO *CMinecraftApp::GetDLCInfoForProductName(WCHAR *pwchProductName) +{ + unordered_map::iterator it= DLCInfo_Full.begin(); + wstring wsProductName=pwchProductName; + + for(int i=0;isecond; + if(wsProductName==pDLCInfo->wsDisplayName) + { + return pDLCInfo; + } + ++it; + } + + return NULL; +} + +#elif defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +#else + +DLC_INFO *CMinecraftApp::GetDLCInfoForFullOfferID(ULONGLONG ullOfferID_Full) +{ + + if(DLCInfo_Full.size()>0) + { + AUTO_VAR(it, DLCInfo_Full.find(ullOfferID_Full)); + + if( it == DLCInfo_Full.end() ) + { + // nothing for this + return NULL; + } + else + { + return it->second; + } + } + else return NULL; +} +#endif + +void CMinecraftApp::EnterSaveNotificationSection() +{ + EnterCriticalSection(&m_saveNotificationCriticalSection); + if( m_saveNotificationDepth++ == 0 ) + { + MinecraftServer::getInstance()->broadcastStartSavingPacket(); + + if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)TRUE); + } + } + LeaveCriticalSection(&m_saveNotificationCriticalSection); +} + +void CMinecraftApp::LeaveSaveNotificationSection() +{ + EnterCriticalSection(&m_saveNotificationCriticalSection); + if( --m_saveNotificationDepth == 0 ) + { + MinecraftServer::getInstance()->broadcastStopSavingPacket(); + + if( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 ) + { + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE); + } + } + LeaveCriticalSection(&m_saveNotificationCriticalSection); +} + + +int CMinecraftApp::RemoteSaveThreadProc( void* lpParameter ) +{ + // The game should be stopped while we are doing this, but the connections ticks may try to create some AABB's or Vec3's + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + + // 4J-PB - Xbox 360 - 163153 - [CRASH] TU17: Code: Multiplayer: During the Autosave in an online Multiplayer session, the game occasionally crashes for one or more Clients + // callstack - > if(tls->tileId != this->id) updateDefaultShape(); + // callstack - > default.exe!WaterlilyTile::getAABB(Level * level, int x, int y, int z) line 38 + 8 bytes C++ + // ... + // default.exe!CMinecraftApp::RemoteSaveThreadProc(void * lpParameter) line 6694 C++ + // host autosave, and the clients can crash on receiving handleMoveEntity when it's a tile within this thread, so need to do the tls for tiles + Tile::CreateNewThreadStorage(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_HOST_SAVING ); + pMinecraft->progressRenderer->progressStage( -1 ); + pMinecraft->progressRenderer->progressStagePercentage(0); + + while( !app.GetGameStarted() && app.GetXuiAction( ProfileManager.GetPrimaryPad() ) == eAppAction_WaitRemoteServerSaveComplete ) + { + // Tick all the games connections + pMinecraft->tickAllConnections(); + Sleep( 100 ); + } + + if( app.GetXuiAction( ProfileManager.GetPrimaryPad() ) != eAppAction_WaitRemoteServerSaveComplete ) + { + // Something cancelled us? + return ERROR_CANCELLED; + } + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_Idle); + + ui.UpdatePlayerBasePositions(); + + Tile::ReleaseThreadStorage(); + + return S_OK; +} + +void CMinecraftApp::ExitGameFromRemoteSave( LPVOID lpParameter ) +{ + int primaryPad = ProfileManager.GetPrimaryPad(); + + UINT uiIDA[3]; + uiIDA[0]=IDS_CONFIRM_CANCEL; + uiIDA[1]=IDS_CONFIRM_OK; + + ui.RequestMessageBox(IDS_EXIT_GAME, IDS_CONFIRM_EXIT_GAME, uiIDA, 2, primaryPad,&CMinecraftApp::ExitGameFromRemoteSaveDialogReturned,NULL, app.GetStringTable(), 0, 0, false); +} + +int CMinecraftApp::ExitGameFromRemoteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + //CScene_Pause* pClass = (CScene_Pause*)pParam; + + // results switched for this dialog + if(result==C4JStorage::EMessage_ResultDecline) + { + app.SetAction(iPad,eAppAction_ExitWorld); + } + else + { +#ifndef _XBOX + // Inform fullscreen progress scene that it's not being cancelled after all + UIScene_FullscreenProgress *pScene = (UIScene_FullscreenProgress *)ui.FindScene(eUIScene_FullscreenProgress); +#ifdef __PS3__ + if(pScene!=NULL) +#else + if (pScene != nullptr) +#endif + { + pScene->SetWasCancelled(false); + } +#else + // Don't have to worry about this on Xbox +#endif + } + return 0; +} + +void CMinecraftApp::SetSpecialTutorialCompletionFlag(int iPad, int index) +{ + if(index >= 0 && index < 32 && GameSettingsA[iPad] != NULL) + { + GameSettingsA[iPad]->uiSpecialTutorialBitmask |= (1<clear(); + + if(BannedListA[iPad].pBannedList) + { + delete [] BannedListA[iPad].pBannedList; + BannedListA[iPad].pBannedList=NULL; + } + } +} + +#ifdef _XBOX_ONE +void CMinecraftApp::AddLevelToBannedLevelList(int iPad, PBANNEDLISTDATA pBannedListData, bool bWriteToTMS) +{ + PlayerUID xuid= pBannedListData->wchPlayerUID; + + AddLevelToBannedLevelList(iPad,xuid,pBannedListData->pszLevelName,bWriteToTMS); +} +#endif + +void CMinecraftApp::AddLevelToBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName, bool bWriteToTMS) +{ + // we will have retrieved the banned level list from TMS, so add this one to it and write it back to TMS + + BANNEDLISTDATA *pBannedListData = new BANNEDLISTDATA; + memset(pBannedListData,0,sizeof(BANNEDLISTDATA)); + +#ifdef _DURANGO + memcpy(&pBannedListData->wchPlayerUID, xuid.toString().c_str(), sizeof(WCHAR)*64); +#else + memcpy(&pBannedListData->xuid, &xuid, sizeof(PlayerUID)); +#endif + strcpy(pBannedListData->pszLevelName,pszLevelName); + m_vBannedListA[iPad]->push_back(pBannedListData); + + if(bWriteToTMS) + { + DWORD dwDataBytes=(DWORD)(sizeof(BANNEDLISTDATA)*m_vBannedListA[iPad]->size()); + PBANNEDLISTDATA pBannedList = (BANNEDLISTDATA *)(new CHAR [dwDataBytes]); + int iCount=0; + for(AUTO_VAR(it, m_vBannedListA[iPad]->begin()); it != m_vBannedListA[iPad]->end(); ++it) + { + PBANNEDLISTDATA pData=*it; + memcpy(&pBannedList[iCount++],pData,sizeof(BANNEDLISTDATA)); + } + + // 4J-PB - write to TMS++ now + + //bool bRes=StorageManager.WriteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList",(PBYTE)pBannedList, dwDataBytes); +#ifdef _XBOX + StorageManager.TMSPP_WriteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,C4JStorage::TMS_UGCTYPE_NONE,"BannedList",(PCHAR) pBannedList, dwDataBytes,NULL,NULL, 0); +#elif defined _XBOX_ONE + StorageManager.TMSPP_WriteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"BannedList",(PBYTE) pBannedList, dwDataBytes,NULL,NULL, 0); +#endif + } + // update telemetry too +} + +bool CMinecraftApp::IsInBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName) +{ + for(AUTO_VAR(it, m_vBannedListA[iPad]->begin()); it != m_vBannedListA[iPad]->end(); ++it) + { + PBANNEDLISTDATA pData=*it; +#ifdef _XBOX_ONE + PlayerUID bannedPlayerUID = pData->wchPlayerUID; + if(IsEqualXUID (bannedPlayerUID,xuid) && (strcmp(pData->pszLevelName,pszLevelName)==0)) +#else + if(IsEqualXUID (pData->xuid,xuid) && (strcmp(pData->pszLevelName,pszLevelName)==0)) +#endif + { + return true; + } + } + + return false; +} + +void CMinecraftApp::RemoveLevelFromBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName) +{ + //bool bFound=false; + //bool bRes; + + // we will have retrieved the banned level list from TMS, so remove this one from it and write it back to TMS + for(AUTO_VAR(it, m_vBannedListA[iPad]->begin()); it != m_vBannedListA[iPad]->end(); ) + { + PBANNEDLISTDATA pBannedListData = *it; + + if(pBannedListData!=NULL) + { +#ifdef _XBOX_ONE + PlayerUID bannedPlayerUID = pBannedListData->wchPlayerUID; + if(IsEqualXUID (bannedPlayerUID,xuid) && (strcmp(pBannedListData->pszLevelName,pszLevelName)==0)) +#else + if(IsEqualXUID (pBannedListData->xuid,xuid) && (strcmp(pBannedListData->pszLevelName,pszLevelName)==0)) +#endif + { + TelemetryManager->RecordUnBanLevel(iPad); + + // match found, so remove this entry + it = m_vBannedListA[iPad]->erase(it); + } + else + { + ++it; + } + } + else + { + ++it; + } + } + + DWORD dwDataBytes=(DWORD)(sizeof(BANNEDLISTDATA)*m_vBannedListA[iPad]->size()); + if(dwDataBytes==0) + { + // wipe the file +#ifdef _XBOX + StorageManager.DeleteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList"); +#elif defined _XBOX_ONE + StorageManager.TMSPP_DeleteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"BannedList",NULL,NULL, 0); +#endif + } + else + { + PBANNEDLISTDATA pBannedList = (BANNEDLISTDATA *)(new BYTE [dwDataBytes]); + + int iSize=(int)m_vBannedListA[iPad]->size(); + for(int i=0;iat(i); + + memcpy(&pBannedList[i],pBannedListData,sizeof(BANNEDLISTDATA)); + } +#ifdef _XBOX + StorageManager.WriteTMSFile(iPad,C4JStorage::eGlobalStorage_TitleUser,L"BannedList",(PBYTE)pBannedList, dwDataBytes); +#elif defined _XBOX_ONE + StorageManager.TMSPP_WriteFile(iPad,C4JStorage::eGlobalStorage_TitleUser,C4JStorage::TMS_FILETYPE_BINARY,L"BannedList",(PBYTE) pBannedList, dwDataBytes,NULL,NULL, 0); +#endif + delete [] pBannedList; + } + + // update telemetry too +} + +// function to add credits for the DLC packs +void CMinecraftApp::AddCreditText(LPCWSTR lpStr) +{ + DebugPrintf("ADDING CREDIT - %ls\n",lpStr); + // add a string from the DLC to a credits vector + SCreditTextItemDef *pCreditStruct = new SCreditTextItemDef; + pCreditStruct->m_eType=eSmallText; + pCreditStruct->m_iStringID[0]=NO_TRANSLATED_STRING; + pCreditStruct->m_iStringID[1]=NO_TRANSLATED_STRING; + pCreditStruct->m_Text=new WCHAR [wcslen(lpStr)+1]; + wcscpy((WCHAR *)pCreditStruct->m_Text,lpStr); + + vDLCCredits.push_back(pCreditStruct); +} + +bool CMinecraftApp::AlreadySeenCreditText(const wstring &wstemp) +{ + + for(unsigned int i=0;i>4; + break; + case eGameHostOption_All: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_ALL); + break; + case eGameHostOption_Tutorial: + // special case - tutorial is offline, but we want the gamertag option, and set Easy mode, structures on, fire on, tnt on, pvp on, trust players on + return ((uiHostSettings&GAME_HOST_OPTION_BITMASK_GAMERTAGS)|GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS|GAME_HOST_OPTION_BITMASK_FIRESPREADS|GAME_HOST_OPTION_BITMASK_TNT|GAME_HOST_OPTION_BITMASK_PVP|GAME_HOST_OPTION_BITMASK_STRUCTURES|1); + break; + case eGameHostOption_LevelType: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_LEVELTYPE); + break; + case eGameHostOption_Structures: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_STRUCTURES); + break; + case eGameHostOption_BonusChest: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_BONUSCHEST); + break; + case eGameHostOption_HasBeenInCreative: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_BEENINCREATIVE); + break; + case eGameHostOption_PvP: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_PVP); + break; + case eGameHostOption_TrustPlayers: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_TRUSTPLAYERS); + break; + case eGameHostOption_TNT: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_TNT); + break; + case eGameHostOption_FireSpreads: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_FIRESPREADS); + break; + case eGameHostOption_CheatsEnabled: + return (uiHostSettings&(GAME_HOST_OPTION_BITMASK_HOSTFLY|GAME_HOST_OPTION_BITMASK_HOSTHUNGER|GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE)); + break; + case eGameHostOption_HostCanFly: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_HOSTFLY); + break; + case eGameHostOption_HostCanChangeHunger: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_HOSTHUNGER); + break; + case eGameHostOption_HostCanBeInvisible: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_HOSTINVISIBLE); + break; + case eGameHostOption_BedrockFog: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_BEDROCKFOG); + break; + case eGameHostOption_DisableSaving: + return (uiHostSettings&GAME_HOST_OPTION_BITMASK_DISABLESAVE); + break; + } + + return false; +} + +bool CMinecraftApp::CanRecordStatsAndAchievements() +{ + // 4J Stu - All of these options give the host player some advantage, so should not allow achievements + return !(app.GetGameHostOption(eGameHostOption_HasBeenInCreative) || + app.GetGameHostOption(eGameHostOption_HostCanBeInvisible) || + app.GetGameHostOption(eGameHostOption_HostCanChangeHunger) || + app.GetGameHostOption(eGameHostOption_HostCanFly)); +} + +void CMinecraftApp::processSchematics(LevelChunk *levelChunk) +{ + m_gameRules.processSchematics(levelChunk); +} + +void CMinecraftApp::processSchematicsLighting(LevelChunk *levelChunk) +{ + m_gameRules.processSchematicsLighting(levelChunk); +} + +void CMinecraftApp::loadDefaultGameRules() +{ + m_gameRules.loadDefaultGameRules(); +} + +void CMinecraftApp::setLevelGenerationOptions(LevelGenerationOptions *levelGen) +{ + m_gameRules.setLevelGenerationOptions(levelGen); +} + +LPCWSTR CMinecraftApp::GetGameRulesString(const wstring &key) +{ + return m_gameRules.GetGameRulesString(key); +} + +unsigned char CMinecraftApp::m_szPNG[8]= +{ + 137,80,78,71,13,10,26,10 +}; + +#define PNG_TAG_tEXt 0x74455874 + +unsigned int CMinecraftApp::FromBigEndian(unsigned int uiValue) +{ +#if defined(__PS3__) || defined(_XBOX) + // Keep it in big endian + return uiValue; +#else + unsigned int uiReturn = ( ( uiValue >> 24 ) & 0x000000ff ) | + ( ( uiValue >> 8 ) & 0x0000ff00 ) | + ( ( uiValue << 8 ) & 0x00ff0000 ) | + ( ( uiValue << 24 ) & 0xff000000 ); + return uiReturn; +#endif +} + +void CMinecraftApp::GetImageTextData(PBYTE pbImageData, DWORD dwImageBytes,unsigned char *pszSeed,unsigned int &uiHostOptions,bool &bHostOptionsRead,DWORD &uiTexturePack) +{ + unsigned char *ucPtr=pbImageData; + unsigned int uiCount=0; + unsigned int uiChunkLen; + unsigned int uiChunkType; + unsigned int uiCRC; + char szKeyword[80]; + + // check it's a png + for(int i=0;i<8;i++) + { + if(m_szPNG[i]!=ucPtr[i]) return; + } + + uiCount+=8; + + while(uiCount> std::hex >> uiHostOptions; + } + else if(strcmp(szKeyword,"4J_TEXTUREPACK")==0) + { + // read the texture pack value + unsigned int uiValueC=0; + unsigned char pszTexturePack[8]; // Hex representation of unsigned int + ZeroMemory(&pszTexturePack,8); + while(*pszKeyword!=0 && (pszKeyword < ucPtr + uiCount + uiChunkLen) && uiValueC < 8) + { + pszTexturePack[uiValueC++]=*pszKeyword; + pszKeyword++; + } + + std::stringstream ss; + ss << pszTexturePack; + ss >> std::hex >> uiTexturePack; + } + } + } + uiCount+=uiChunkLen; + uiCRC=*(unsigned int*)&ucPtr[uiCount]; + uiCRC=FromBigEndian(uiCRC); + uiCount+=sizeof(int); + } + + return; +} + +unsigned int CMinecraftApp::CreateImageTextData(PBYTE bTextMetadata, __int64 seed, bool hasSeed, unsigned int uiHostOptions, unsigned int uiTexturePackId) +{ + int iTextMetadataBytes = 0; + if(hasSeed) + { + strcpy((char *)bTextMetadata,"4J_SEED"); + _i64toa_s(seed,(char *)&bTextMetadata[8],42,10); + + // get the length + iTextMetadataBytes+=8; + while(bTextMetadata[iTextMetadataBytes]!=0) iTextMetadataBytes++; + ++iTextMetadataBytes; // Add a null terminator at the end of the seed value + } + + // Save the host options that this world was last played with + strcpy((char *)&bTextMetadata[iTextMetadataBytes],"4J_HOSTOPTIONS"); + _itoa_s(uiHostOptions,(char *)&bTextMetadata[iTextMetadataBytes+15],9,16); + + iTextMetadataBytes += 15; + while(bTextMetadata[iTextMetadataBytes]!=0) iTextMetadataBytes++; + ++iTextMetadataBytes; // Add a null terminator at the end of the host options value + + // Save the texture pack id + strcpy((char *)&bTextMetadata[iTextMetadataBytes],"4J_TEXTUREPACK"); + _itoa_s(uiTexturePackId,(char *)&bTextMetadata[iTextMetadataBytes+15],9,16); + + iTextMetadataBytes += 15; + while(bTextMetadata[iTextMetadataBytes]!=0) iTextMetadataBytes++; + + return iTextMetadataBytes; +} + +void CMinecraftApp::AddTerrainFeaturePosition(_eTerrainFeatureType eFeatureType,int x,int z) +{ + // check we don't already have this in + for(AUTO_VAR(it, m_vTerrainFeatures.begin()); it < m_vTerrainFeatures.end(); ++it) + { + FEATURE_DATA *pFeatureData=*it; + + if((pFeatureData->eTerrainFeature==eFeatureType) &&(pFeatureData->x==x) && (pFeatureData->z==z)) return; + } + + FEATURE_DATA *pFeatureData= new FEATURE_DATA; + pFeatureData->eTerrainFeature=eFeatureType; + pFeatureData->x=x; + pFeatureData->z=z; + + m_vTerrainFeatures.push_back(pFeatureData); +} + +_eTerrainFeatureType CMinecraftApp::IsTerrainFeature(int x,int z) +{ + for(AUTO_VAR(it, m_vTerrainFeatures.begin()); it < m_vTerrainFeatures.end(); ++it) + { + FEATURE_DATA *pFeatureData=*it; + + if((pFeatureData->x==x) && (pFeatureData->z==z)) return pFeatureData->eTerrainFeature; + } + + return eTerrainFeature_None; +} + +bool CMinecraftApp::GetTerrainFeaturePosition(_eTerrainFeatureType eType,int *pX, int *pZ) +{ + for(AUTO_VAR(it, m_vTerrainFeatures.begin()); it < m_vTerrainFeatures.end(); ++it) + { + FEATURE_DATA *pFeatureData=*it; + + if(pFeatureData->eTerrainFeature==eType) + { + *pX=pFeatureData->x; + *pZ=pFeatureData->z; + return true; + } + } + + return false; +} + +void CMinecraftApp::ClearTerrainFeaturePosition() +{ + FEATURE_DATA *pFeatureData; + while(m_vTerrainFeatures.size()>0) + { + pFeatureData = m_vTerrainFeatures.back(); + m_vTerrainFeatures.pop_back(); + delete pFeatureData; + } +} + +void CMinecraftApp::UpdatePlayerInfo(BYTE networkSmallId, SHORT playerColourIndex, unsigned int playerGamePrivileges) +{ + for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) + { + if(m_playerColours[i]==networkSmallId) + { + m_playerColours[i] = 0; + m_playerGamePrivileges[i] = 0; + } + } + if(playerColourIndex >=0 && playerColourIndex < MINECRAFT_NET_MAX_PLAYERS) + { + m_playerColours[playerColourIndex] = networkSmallId; + m_playerGamePrivileges[playerColourIndex] = playerGamePrivileges; + } +} + +short CMinecraftApp::GetPlayerColour(BYTE networkSmallId) +{ + short index = -1; + for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) + { + if(m_playerColours[i]==networkSmallId) + { + index = i; + break; + } + } + return index; +} + + +unsigned int CMinecraftApp::GetPlayerPrivileges(BYTE networkSmallId) +{ + unsigned int privileges = 0; + for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) + { + if(m_playerColours[i]==networkSmallId) + { + privileges = m_playerGamePrivileges[i]; + break; + } + } + return privileges; +} + +wstring CMinecraftApp::getEntityName(eINSTANCEOF type) +{ + switch(type) + { + case eTYPE_WOLF: + return app.GetString(IDS_WOLF); + case eTYPE_CREEPER: + return app.GetString(IDS_CREEPER); + case eTYPE_SKELETON: + return app.GetString(IDS_SKELETON); + case eTYPE_SPIDER: + return app.GetString(IDS_SPIDER); + case eTYPE_ZOMBIE: + return app.GetString(IDS_ZOMBIE); + case eTYPE_PIGZOMBIE: + return app.GetString(IDS_PIGZOMBIE); + case eTYPE_ENDERMAN: + return app.GetString(IDS_ENDERMAN); + case eTYPE_SILVERFISH: + return app.GetString(IDS_SILVERFISH); + case eTYPE_CAVESPIDER: + return app.GetString(IDS_CAVE_SPIDER); + case eTYPE_GHAST: + return app.GetString(IDS_GHAST); + case eTYPE_SLIME: + return app.GetString(IDS_SLIME); + case eTYPE_ARROW: + return app.GetString(IDS_ITEM_ARROW); + case eTYPE_ENDERDRAGON: + return app.GetString(IDS_ENDERDRAGON); + case eTYPE_BLAZE: + return app.GetString(IDS_BLAZE); + case eTYPE_LAVASLIME: + return app.GetString(IDS_LAVA_SLIME); + // 4J-PB - fix for #107167 - Customer Encountered: TU12: Content: UI: There is no information what killed Player after being slain by Iron Golem. + case eTYPE_VILLAGERGOLEM: + return app.GetString(IDS_IRONGOLEM); + + }; + + return L""; +} + +DWORD CMinecraftApp::m_dwContentTypeA[e_Marketplace_MAX]= +{ + XMARKETPLACE_OFFERING_TYPE_CONTENT, // e_DLC_SkinPack, e_DLC_TexturePacks, e_DLC_MashupPacks +#ifndef _XBOX_ONE + XMARKETPLACE_OFFERING_TYPE_THEME, // e_DLC_Themes + XMARKETPLACE_OFFERING_TYPE_AVATARITEM, // e_DLC_AvatarItems + XMARKETPLACE_OFFERING_TYPE_TILE, // e_DLC_Gamerpics +#endif +}; + +unsigned int CMinecraftApp::AddDLCRequest(eDLCMarketplaceType eType, bool bPromote) +{ + // lock access + EnterCriticalSection(&csDLCDownloadQueue); + + // If it's already in there, promote it to the top of the list + int iPosition=0; + for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it) + { + DLCRequest *pCurrent = *it; + + if(pCurrent->dwType==m_dwContentTypeA[eType]) + { + // already got this in the list + if(pCurrent->eState == e_DLC_ContentState_Retrieving || pCurrent->eState == e_DLC_ContentState_Retrieved) + { + // already retrieved this + LeaveCriticalSection(&csDLCDownloadQueue); + return 0; + } + else + { + // promote + if(bPromote) + { + m_DLCDownloadQueue.erase(m_DLCDownloadQueue.begin()+iPosition); + m_DLCDownloadQueue.insert(m_DLCDownloadQueue.begin(),pCurrent); + } + LeaveCriticalSection(&csDLCDownloadQueue); + return 0; + } + } + iPosition++; + } + + DLCRequest *pDLCreq = new DLCRequest; + pDLCreq->dwType=m_dwContentTypeA[eType]; + pDLCreq->eState=e_DLC_ContentState_Idle; + + m_DLCDownloadQueue.push_back(pDLCreq); + + m_bAllDLCContentRetrieved=false; + LeaveCriticalSection(&csDLCDownloadQueue); + + app.DebugPrintf("[Consoles_App] Added DLC request.\n"); + return 1; +} + +unsigned int CMinecraftApp::AddTMSPPFileTypeRequest(eDLCContentType eType, bool bPromote) +{ +#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) + // lock access + EnterCriticalSection(&csTMSPPDownloadQueue); + + // If it's already in there, promote it to the top of the list + int iPosition=0; + //ignore promoting for now + /* + bool bPromoted=false; + + + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(pCurrent->eType==eType) + { + if(!(pCurrent->eState == e_TMS_ContentState_Retrieving || pCurrent->eState == e_TMS_ContentState_Retrieved)) + { + // promote + if(bPromote) + { + m_TMSPPDownloadQueue.erase(m_TMSPPDownloadQueue.begin()+iPosition); + m_TMSPPDownloadQueue.insert(m_TMSPPDownloadQueue.begin(),pCurrent); + bPromoted=true; + } + } + } + iPosition++; + } + + if(bPromoted) + { + // re-ordered the list, so leave now + LeaveCriticalSection(&csTMSPPDownloadQueue); + return 0; + } + */ + + // special case for data files (not image files) + if(eType==e_DLC_TexturePackData) + { + + + int iCount=GetDLCInfoFullOffersCount(); + + for(int i=0;ieDLCType==e_DLC_TexturePacks) || (pDLC->eDLCType==e_DLC_MashupPacks)) + { + // first check if the image is already in the memory textures, since we might be loading some from the Title Update partition + if(pDLC->wchDataFile[0]!=0) + { + //WCHAR *cString = pDLC->wchDataFile; + // 4J-PB - shouldn't check this here - let the TMS files override it, so if they are on TMS, we'll take them first + //int iIndex = app.GetLocalTMSFileIndex(pDLC->wchDataFile,true); + + //if(iIndex!=-1) + { + bool bPresent = app.IsFileInTPD(pDLC->iConfig); + + if(!bPresent) + { + // this may already be present in the vector because of a previous trial/full offer + + bool bAlreadyInQueue=false; + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(wcscmp(pDLC->wchDataFile,pCurrent->wchFilename)==0) + { + bAlreadyInQueue=true; + break; + } + } + + if(!bAlreadyInQueue) + { + TMSPPRequest *pTMSPPreq = new TMSPPRequest; + + pTMSPPreq->CallbackFunc=&CMinecraftApp::TMSPPFileReturned; + pTMSPPreq->lpCallbackParam=this; + pTMSPPreq->eStorageFacility=C4JStorage::eGlobalStorage_Title; + pTMSPPreq->eFileTypeVal=C4JStorage::TMS_FILETYPE_BINARY; + memcpy(pTMSPPreq->wchFilename,pDLC->wchDataFile,sizeof(WCHAR)*MAX_BANNERNAME_SIZE); + pTMSPPreq->eType=e_DLC_TexturePackData; + pTMSPPreq->eState=e_TMS_ContentState_Queued; + m_bAllTMSContentRetrieved=false; + m_TMSPPDownloadQueue.push_back(pTMSPPreq); + } + } + else + { + app.DebugPrintf("Texture data already present in the TPD\n"); + } + } + } + } + } + } + else + { // for all the files of type eType, add them to the download list + + // run through the trial offers first, then the full offers. Any duplicates won't be added to the download queue + int iCount; +#ifdef _XBOX // Only trial offers on Xbox 360 + iCount=GetDLCInfoTrialOffersCount(); + for(int i=0;ieDLCType==eType) + { + + WCHAR *cString = pDLC->wchBanner; + + // 4J-PB - shouldn't check this here - let the TMS files override it, so if they are on TMS, we'll take them first + // is the file in the TMS XZP? + //int iIndex = app.GetLocalTMSFileIndex(cString,true); + + //if(iIndex!=-1) + { + bool bPresent = app.IsFileInMemoryTextures(cString); + + if(!bPresent) // retrieve it from TMSPP + { + bool bAlreadyInQueue=false; + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(wcscmp(pDLC->wchBanner,pCurrent->wchFilename)==0) + { + bAlreadyInQueue=true; + break; + } + } + + if(!bAlreadyInQueue) + { + TMSPPRequest *pTMSPPreq = new TMSPPRequest; + + pTMSPPreq->CallbackFunc=&CMinecraftApp::TMSPPFileReturned; + pTMSPPreq->lpCallbackParam=this; + pTMSPPreq->eStorageFacility=C4JStorage::eGlobalStorage_Title; + pTMSPPreq->eFileTypeVal=C4JStorage::TMS_FILETYPE_BINARY; + //wcstombs(pTMSPPreq->szFilename,pDLC->wchBanner,MAX_TMSFILENAME_SIZE); + memcpy(pTMSPPreq->wchFilename,pDLC->wchBanner,sizeof(WCHAR)*MAX_BANNERNAME_SIZE); + pTMSPPreq->eType=eType; + pTMSPPreq->eState=e_TMS_ContentState_Queued; + + m_bAllTMSContentRetrieved=false; + m_TMSPPDownloadQueue.push_back(pTMSPPreq); + app.DebugPrintf("===m_TMSPPDownloadQueue Adding %ls, q size is %d\n",pTMSPPreq->wchFilename,m_TMSPPDownloadQueue.size()); + } + } + } + } + } +#endif + // and the full offers + + iCount=GetDLCInfoFullOffersCount(); + for(int i=0;iwchType,wchDLCTypeNames[eType])==0) + if(pDLC->eDLCType==eType) + { + // first check if the image is already in the memory textures, since we might be loading some from the Title Update partition + + WCHAR *cString = pDLC->wchBanner; + // 4J-PB - shouldn't check this here - let the TMS files override it, so if they are on TMS, we'll take them first + //int iIndex = app.GetLocalTMSFileIndex(cString,true); + + //if(iIndex!=-1) + { + bool bPresent = app.IsFileInMemoryTextures(cString); + + if(!bPresent) + { + // this may already be present in the vector because of a previous trial/full offer + + bool bAlreadyInQueue=false; + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(wcscmp(pDLC->wchBanner,pCurrent->wchFilename)==0) + { + bAlreadyInQueue=true; + break; + } + } + + if(!bAlreadyInQueue) + { + //app.DebugPrintf("Adding a request to the TMSPP download queue - %ls\n",pDLC->wchBanner); + TMSPPRequest *pTMSPPreq = new TMSPPRequest; + ZeroMemory(pTMSPPreq,sizeof(TMSPPRequest)); + + pTMSPPreq->CallbackFunc=&CMinecraftApp::TMSPPFileReturned; + pTMSPPreq->lpCallbackParam=this; + // 4J-PB - testing for now + //pTMSPPreq->eStorageFacility=C4JStorage::eGlobalStorage_TitleUser; + pTMSPPreq->eStorageFacility=C4JStorage::eGlobalStorage_Title; + pTMSPPreq->eFileTypeVal=C4JStorage::TMS_FILETYPE_BINARY; + //wcstombs(pTMSPPreq->szFilename,pDLC->wchBanner,MAX_TMSFILENAME_SIZE); + + memcpy(pTMSPPreq->wchFilename,pDLC->wchBanner,sizeof(WCHAR)*MAX_BANNERNAME_SIZE); + pTMSPPreq->eType=eType; + pTMSPPreq->eState=e_TMS_ContentState_Queued; + m_bAllTMSContentRetrieved=false; + m_TMSPPDownloadQueue.push_back(pTMSPPreq); + app.DebugPrintf("===m_TMSPPDownloadQueue Adding %ls, q size is %d\n",pTMSPPreq->wchFilename,m_TMSPPDownloadQueue.size()); + } + } + } + } + } + } + + LeaveCriticalSection(&csTMSPPDownloadQueue); +#endif + return 1; +} + +bool CMinecraftApp::CheckTMSDLCCanStop() +{ + EnterCriticalSection(&csTMSPPDownloadQueue); + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(pCurrent->eState==e_TMS_ContentState_Retrieving) + { + LeaveCriticalSection(&csTMSPPDownloadQueue); + return false; + } + } + LeaveCriticalSection(&csTMSPPDownloadQueue); + + return true; +} + + +bool CMinecraftApp::RetrieveNextDLCContent() +{ + // If there's already a retrieve in progress, quit + // we may have re-ordered the list, so need to check every item + + // is there a primary player and a network connection? + int primPad = ProfileManager.GetPrimaryPad(); + if ( primPad == -1 || !ProfileManager.IsSignedInLive(primPad) ) + { + return true; // 4J-JEV: We need to wait until the primary player is online. + } + + EnterCriticalSection(&csDLCDownloadQueue); + for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it) + { + DLCRequest *pCurrent = *it; + + if(pCurrent->eState==e_DLC_ContentState_Retrieving) + { + LeaveCriticalSection(&csDLCDownloadQueue); + return true; + } + } + + // Now look for the next retrieval + for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it) + { + DLCRequest *pCurrent = *it; + + if(pCurrent->eState==e_DLC_ContentState_Idle) + { +#ifdef _DEBUG + app.DebugPrintf("RetrieveNextDLCContent - type = %d\n",pCurrent->dwType); +#endif + + C4JStorage::EDLCStatus status = StorageManager.GetDLCOffers(ProfileManager.GetPrimaryPad(), &CMinecraftApp::DLCOffersReturned, this, pCurrent->dwType); + if(status==C4JStorage::EDLC_Pending) + { + pCurrent->eState=e_DLC_ContentState_Retrieving; + } + else + { + // no content of this type, or some other problem + app.DebugPrintf("RetrieveNextDLCContent - PROBLEM\n"); + pCurrent->eState=e_DLC_ContentState_Retrieved; + } + LeaveCriticalSection(&csDLCDownloadQueue); + return true; + } + } + LeaveCriticalSection(&csDLCDownloadQueue); + + app.DebugPrintf("[Consoles_App] Finished downloading dlc content.\n"); + return false; +} + +#if !defined(__PS3__) && !defined(__ORBIS__) && !defined(__PSVITA__) +#ifdef _XBOX_ONE +int CMinecraftApp::TMSPPFileReturned(LPVOID pParam,int iPad,int iUserData,LPVOID lpvData, WCHAR* wchFilename) +{ + C4JStorage::PTMSPP_FILEDATA pFileData=(C4JStorage::PTMSPP_FILEDATA)lpvData; +#else +int CMinecraftApp::TMSPPFileReturned(LPVOID pParam,int iPad,int iUserData,C4JStorage::PTMSPP_FILEDATA pFileData, LPCSTR szFilename) +{ +#endif + + CMinecraftApp* pClass = (CMinecraftApp *) pParam; + + // find the right one in the vector + EnterCriticalSection(&pClass->csTMSPPDownloadQueue); + for(AUTO_VAR(it, pClass->m_TMSPPDownloadQueue.begin()); it != pClass->m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; +#if defined(_XBOX) || defined(_WINDOWS64) + char szFile[MAX_TMSFILENAME_SIZE]; + wcstombs(szFile,pCurrent->wchFilename,MAX_TMSFILENAME_SIZE); + + + if(strcmp(szFilename,szFile)==0) +#elif _XBOX_ONE + if(wcscmp(wchFilename,pCurrent->wchFilename)==0) +#endif + { + // set this to retrieved whether it found it or not + pCurrent->eState=e_TMS_ContentState_Retrieved; + + if(pFileData!=NULL) + { + +#ifdef _XBOX_ONE + + + switch(pCurrent->eType) + { + case e_DLC_TexturePackData: + { + // 4J-PB - we need to allocate memory for the file data and copy into it, since the current data is a reference into the blob download memory + PBYTE pbData = new BYTE [pFileData->dwSize]; + memcpy(pbData,pFileData->pbData,pFileData->dwSize); + + pClass->m_vTMSPPData.push_back(pbData); + app.DebugPrintf("Got texturepack data\n"); + // get the config value for the texture pack + int iConfig=app.GetTPConfigVal(pCurrent->wchFilename); + app.AddMemoryTPDFile(iConfig, pbData, pFileData->dwSize); + } + break; + default: + // 4J-PB - check the data is an image + if(pFileData->pbData[0]==0x89) + { + // 4J-PB - we need to allocate memory for the file data and copy into it, since the current data is a reference into the blob download memory + PBYTE pbData = new BYTE [pFileData->dwSize]; + memcpy(pbData,pFileData->pbData,pFileData->dwSize); + + pClass->m_vTMSPPData.push_back(pbData); + app.DebugPrintf("Got image data - %ls\n",pCurrent->wchFilename); + app.AddMemoryTextureFile(pCurrent->wchFilename, pbData, pFileData->dwSize); + } + else + { + app.DebugPrintf("Got image data, but it's not a png - %ls\n",pCurrent->wchFilename); + } + break; + } + +#else + switch(pCurrent->eType) + { + case e_DLC_TexturePackData: + { + app.DebugPrintf("--- Got texturepack data %ls\n",pCurrent->wchFilename); + // get the config value for the texture pack + int iConfig=app.GetTPConfigVal(pCurrent->wchFilename); + app.AddMemoryTPDFile(iConfig, pFileData->pbData, pFileData->dwSize); + } + break; + default: + app.DebugPrintf("--- Got image data - %ls\n",pCurrent->wchFilename); + app.AddMemoryTextureFile(pCurrent->wchFilename, pFileData->pbData, pFileData->dwSize); + break; + } +#endif + } + else + { +#ifdef _XBOX_ONE + app.DebugPrintf("TMSImageReturned failed (%ls)...\n",wchFilename); +#else + app.DebugPrintf("TMSImageReturned failed (%s)...\n",szFilename); +#endif + } + break; + } + + } + LeaveCriticalSection(&pClass->csTMSPPDownloadQueue); + + return 0; +} +#endif + +bool CMinecraftApp::RetrieveNextTMSPPContent() +{ +#if defined _XBOX || defined _XBOX_ONE + // If there's already a retrieve in progress, quit + // we may have re-ordered the list, so need to check every item + + // is there a primary player and a network connection? + if(ProfileManager.GetPrimaryPad()==-1) return false; + + if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())==false) return false; + + EnterCriticalSection(&csTMSPPDownloadQueue); + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(pCurrent->eState==e_TMS_ContentState_Retrieving) + { + app.DebugPrintf("."); + LeaveCriticalSection(&csTMSPPDownloadQueue); + return true; + } + } + + // Now look for the next retrieval + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + if(pCurrent->eState==e_TMS_ContentState_Queued) + { + // 4J-PB - the file may be in the local TMS files, but try to retrieve it from the remote TMS in case it's been changed. If it's not in the list of TMS files, this will + // return right away with a ETMSStatus_Fail_ReadDetailsNotRetrieved +#ifdef _XBOX + char szFilename[MAX_TMSFILENAME_SIZE]; + wcstombs(szFilename,pCurrent->wchFilename,MAX_TMSFILENAME_SIZE); + + app.DebugPrintf("\nRetrieveNextTMSPPContent - type = %d, %s\n",pCurrent->eType,szFilename); + + C4JStorage::ETMSStatus status=StorageManager.TMSPP_ReadFile(ProfileManager.GetPrimaryPad(),pCurrent->eStorageFacility,pCurrent->eFileTypeVal,szFilename,pCurrent->CallbackFunc,this); + switch(status) + { + case C4JStorage::ETMSStatus_Pending: + pCurrent->eState=e_TMS_ContentState_Retrieving; + break; + case C4JStorage::ETMSStatus_Idle: + pCurrent->eState=e_TMS_ContentState_Retrieved; + break; + case C4JStorage::ETMSStatus_Fail_ReadInProgress: + case C4JStorage::ETMSStatus_ReadInProgress: + pCurrent->eState=e_TMS_ContentState_Retrieving; + if(pCurrent->eState==C4JStorage::ETMSStatus_Fail_ReadInProgress) + { + app.DebugPrintf("TMSPP_ReadFile failed - read in progress\n"); + Sleep(50); + LeaveCriticalSection(&csTMSPPDownloadQueue); + return false; + } + break; + default: + pCurrent->eState=e_TMS_ContentState_Retrieved; + break; + } +#else + eTitleStorageState status; + app.DebugPrintf("RetrieveNextTMSPPContent - type = %d, %ls\n",pCurrent->eType,pCurrent->wchFilename); + //eTitleStorageState status=StorageManager.TMSPP_ReadFile(ProfileManager.GetPrimaryPad(),pCurrent->eStorageFacility,pCurrent->eFileTypeVal,pCurrent->wchFilename,pCurrent->CallbackFunc,this,0); + if(0)//wcscmp(pCurrent->wchFilename,L"TP01.png")==0) + { + // TP01 fails because the blob size returned is bigger than the global metadata says it should be + status=eTitleStorage_readerror; + } + else + { + status=StorageManager.TMSPP_ReadFile(ProfileManager.GetPrimaryPad(),pCurrent->eStorageFacility,pCurrent->eFileTypeVal,pCurrent->wchFilename,pCurrent->CallbackFunc,this,0); + } + switch(status) + { + case eTitleStorage_pending: + pCurrent->eState=e_TMS_ContentState_Retrieving; + break; + case eTitleStorage_idle: + pCurrent->eState=e_TMS_ContentState_Retrieved; + break; + case eTitleStorage_busy: + // try again next time + { + app.DebugPrintf("@@@@@@@@@@@@@@@@@ TMSPP_ReadFile failed - busy (probably reading already)\n"); + Sleep(50); + LeaveCriticalSection(&csTMSPPDownloadQueue); + return false; + } + break; + default: + pCurrent->eState=e_TMS_ContentState_Retrieved; + break; + } +#endif + + + + LeaveCriticalSection(&csTMSPPDownloadQueue); + return true; + } + } + + LeaveCriticalSection(&csTMSPPDownloadQueue); + +#endif + return false; +} + +void CMinecraftApp::TickDLCOffersRetrieved() +{ + if(!m_bAllDLCContentRetrieved) + { + if (!app.RetrieveNextDLCContent()) + { + app.DebugPrintf("[Consoles_App] All content retrieved.\n"); + m_bAllDLCContentRetrieved=true; + } + } +} +void CMinecraftApp::ClearAndResetDLCDownloadQueue() +{ + app.DebugPrintf("[Consoles_App] Clear and reset download queue.\n"); + + int iPosition=0; + EnterCriticalSection(&csTMSPPDownloadQueue); + for(AUTO_VAR(it, m_DLCDownloadQueue.begin()); it != m_DLCDownloadQueue.end(); ++it) + { + DLCRequest *pCurrent = *it; + + delete pCurrent; + iPosition++; + } + m_DLCDownloadQueue.clear(); + m_bAllDLCContentRetrieved=true; + LeaveCriticalSection(&csTMSPPDownloadQueue); +} + +void CMinecraftApp::TickTMSPPFilesRetrieved() +{ + if(m_bTickTMSDLCFiles && !m_bAllTMSContentRetrieved) + { + if(app.RetrieveNextTMSPPContent()==false) + { + m_bAllTMSContentRetrieved=true; + } + } +} +void CMinecraftApp::ClearTMSPPFilesRetrieved() +{ + int iPosition=0; + EnterCriticalSection(&csTMSPPDownloadQueue); + for(AUTO_VAR(it, m_TMSPPDownloadQueue.begin()); it != m_TMSPPDownloadQueue.end(); ++it) + { + TMSPPRequest *pCurrent = *it; + + delete pCurrent; + iPosition++; + } + m_TMSPPDownloadQueue.clear(); + m_bAllTMSContentRetrieved=true; + LeaveCriticalSection(&csTMSPPDownloadQueue); +} + +int CMinecraftApp::DLCOffersReturned(void *pParam, int iOfferC, DWORD dwType, int iPad) +{ + CMinecraftApp* pClass = (CMinecraftApp *) pParam; + + // find the right one in the vector + EnterCriticalSection(&pClass->csTMSPPDownloadQueue); + for(AUTO_VAR(it, pClass->m_DLCDownloadQueue.begin()); it != pClass->m_DLCDownloadQueue.end(); ++it) + { + DLCRequest *pCurrent = *it; + + // avatar items are coming back as type Content, so we can't trust the type setting + if(pCurrent->dwType==dwType) + { + pClass->m_iDLCOfferC = iOfferC; + app.DebugPrintf("DLCOffersReturned - type %d, count %d - setting to retrieved\n",dwType,iOfferC); + pCurrent->eState=e_DLC_ContentState_Retrieved; + break; + } + } + LeaveCriticalSection(&pClass->csTMSPPDownloadQueue); + return 0; +} + +eDLCContentType CMinecraftApp::Find_eDLCContentType(DWORD dwType) +{ + for(int i=0;idwType==m_dwContentTypeA[eType]) && (pCurrent->eState==e_DLC_ContentState_Retrieved)) + { + LeaveCriticalSection(&csDLCDownloadQueue); + return true; + } + } + LeaveCriticalSection(&csDLCDownloadQueue); + return false; +} + +void CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, SKIN_BOX *SkinBoxA, DWORD dwSkinBoxC) +{ + EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER); + Model *pModel = renderer->getModel(); + vector *pvModelPart = new vector; + vector *pvSkinBoxes = new vector; + + EnterCriticalSection( &csAdditionalModelParts ); + EnterCriticalSection( &csAdditionalSkinBoxes ); + + app.DebugPrintf("*** SetAdditionalSkinBoxes - Inserting model parts for skin %d from array of Skin Boxes\n",dwSkinID&0x0FFFFFFF); + + // convert the skin boxes into model parts, and add to the humanoid model + for(unsigned int i=0;iAddOrRetrievePart(&SkinBoxA[i]); + pvModelPart->push_back(pModelPart); + pvSkinBoxes->push_back(&SkinBoxA[i]); + } + } + + + m_AdditionalModelParts.insert( std::pair *>(dwSkinID, pvModelPart) ); + m_AdditionalSkinBoxes.insert( std::pair *>(dwSkinID, pvSkinBoxes) ); + + LeaveCriticalSection( &csAdditionalSkinBoxes ); + LeaveCriticalSection( &csAdditionalModelParts ); + +} + +vector * CMinecraftApp::SetAdditionalSkinBoxes(DWORD dwSkinID, vector *pvSkinBoxA) +{ + EntityRenderer *renderer = EntityRenderDispatcher::instance->getRenderer(eTYPE_PLAYER); + Model *pModel = renderer->getModel(); + vector *pvModelPart = new vector; + + EnterCriticalSection( &csAdditionalModelParts ); + EnterCriticalSection( &csAdditionalSkinBoxes ); + app.DebugPrintf("*** SetAdditionalSkinBoxes - Inserting model parts for skin %d from array of Skin Boxes\n",dwSkinID&0x0FFFFFFF); + + // convert the skin boxes into model parts, and add to the humanoid model + for(AUTO_VAR(it, pvSkinBoxA->begin());it != pvSkinBoxA->end(); ++it) + { + if(pModel) + { + ModelPart *pModelPart=pModel->AddOrRetrievePart(*it); + pvModelPart->push_back(pModelPart); + } + } + + m_AdditionalModelParts.insert( std::pair *>(dwSkinID, pvModelPart) ); + m_AdditionalSkinBoxes.insert( std::pair *>(dwSkinID, pvSkinBoxA) ); + + LeaveCriticalSection( &csAdditionalSkinBoxes ); + LeaveCriticalSection( &csAdditionalModelParts ); + return pvModelPart; +} + + +vector *CMinecraftApp::GetAdditionalModelParts(DWORD dwSkinID) +{ + EnterCriticalSection( &csAdditionalModelParts ); + vector *pvModelParts=NULL; + if(m_AdditionalModelParts.size()>0) + { + AUTO_VAR(it, m_AdditionalModelParts.find(dwSkinID)); + if(it!=m_AdditionalModelParts.end()) + { + pvModelParts = (*it).second; + } + } + + LeaveCriticalSection( &csAdditionalModelParts ); + return pvModelParts; +} + +vector *CMinecraftApp::GetAdditionalSkinBoxes(DWORD dwSkinID) +{ + EnterCriticalSection( &csAdditionalSkinBoxes ); + vector *pvSkinBoxes=NULL; + if(m_AdditionalSkinBoxes.size()>0) + { + AUTO_VAR(it,m_AdditionalSkinBoxes.find(dwSkinID)); + if(it!=m_AdditionalSkinBoxes.end()) + { + pvSkinBoxes = (*it).second; + } + } + + LeaveCriticalSection( &csAdditionalSkinBoxes ); + return pvSkinBoxes; +} + +unsigned int CMinecraftApp::GetAnimOverrideBitmask(DWORD dwSkinID) +{ + EnterCriticalSection( &csAnimOverrideBitmask ); + unsigned int uiAnimOverrideBitmask=0L; + + if(m_AnimOverrides.size()>0) + { + AUTO_VAR(it, m_AnimOverrides.find(dwSkinID)); + if(it!=m_AnimOverrides.end()) + { + uiAnimOverrideBitmask = (*it).second; + } + } + + LeaveCriticalSection( &csAnimOverrideBitmask ); + return uiAnimOverrideBitmask; +} + +void CMinecraftApp::SetAnimOverrideBitmask(DWORD dwSkinID,unsigned int uiAnimOverrideBitmask) +{ + // Make thread safe + EnterCriticalSection( &csAnimOverrideBitmask ); + + if(m_AnimOverrides.size()>0) + { + AUTO_VAR(it, m_AnimOverrides.find(dwSkinID)); + if(it!=m_AnimOverrides.end()) + { + LeaveCriticalSection( &csAnimOverrideBitmask ); + return; // already in here + } + } + m_AnimOverrides.insert( std::pair(dwSkinID, uiAnimOverrideBitmask) ); + LeaveCriticalSection( &csAnimOverrideBitmask ); +} + +DWORD CMinecraftApp::getSkinIdFromPath(const wstring &skin) +{ + bool dlcSkin = false; + unsigned int skinId = 0; + + if(skin.size() >= 14) + { + dlcSkin = skin.substr(0,3).compare(L"dlc") == 0; + + wstring skinValue = skin.substr(7,skin.size()); + skinValue = skinValue.substr(0,skinValue.find_first_of(L'.')); + + std::wstringstream ss; + // 4J Stu - dlc skins are numbered using decimal to make it easier for artists/people to number manually + // Everything else is numbered using hex + if(dlcSkin) + ss << std::dec << skinValue.c_str(); + else + ss << std::hex << skinValue.c_str(); + ss >> skinId; + + skinId = MAKE_SKIN_BITMASK(dlcSkin, skinId); + } + return skinId; +} + +wstring CMinecraftApp::getSkinPathFromId(DWORD skinId) +{ + // 4J Stu - This function maps the encoded DWORD we store in the player profile + // to a filename that is stored as a memory texture and shared between systems in game + wchar_t chars[256]; + if( GET_IS_DLC_SKIN_FROM_BITMASK(skinId) ) + { + // 4J Stu - DLC skins are numbered using decimal rather than hex to make it easier to number manually + swprintf(chars, 256, L"dlcskin%08d.png", GET_DLC_SKIN_ID_FROM_BITMASK(skinId)); + + } + else + { + DWORD ugcSkinIndex = GET_UGC_SKIN_ID_FROM_BITMASK(skinId); + DWORD defaultSkinIndex = GET_DEFAULT_SKIN_ID_FROM_BITMASK(skinId); + if( ugcSkinIndex == 0 ) + { + swprintf(chars, 256, L"defskin%08X.png",defaultSkinIndex); + } + else + { + swprintf(chars, 256, L"ugcskin%08X.png",ugcSkinIndex); + } + } + return chars; +} + + +int CMinecraftApp::TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ +#ifdef _XBOX + if(result!=C4JStorage::EMessage_Cancelled) + { + if(app.GetRequiredTexturePackID()!=0) + { + // we need to enable background downloading for the DLC + XBackgroundDownloadSetMode(XBACKGROUND_DOWNLOAD_MODE_ALWAYS_ALLOW); + + ULONGLONG ullOfferID_Full; + ULONGLONG ullIndexA[1]; + app.GetDLCFullOfferIDForPackID(app.GetRequiredTexturePackID(),&ullOfferID_Full); + + if( result==C4JStorage::EMessage_ResultAccept ) // Full version + { + ullIndexA[0]=ullOfferID_Full; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + else // trial version + { + DLC_INFO *pDLCInfo=app.GetDLCInfoForFullOfferID(ullOfferID_Full); + ullIndexA[0]=pDLCInfo->ullOfferID_Trial; + StorageManager.InstallOffer(1,ullIndexA,NULL,NULL); + } + } + } +#endif + return 0; +} + +int CMinecraftApp::getArchiveFileSize(const wstring &filename) +{ + TexturePack *tPack = NULL; + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected(); + if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) + { + return tPack->getArchiveFile()->getFileSize(filename); + } + else return m_mediaArchive->getFileSize(filename); +} + +bool CMinecraftApp::hasArchiveFile(const wstring &filename) +{ + TexturePack *tPack = NULL; + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected(); + if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) return true; + else return m_mediaArchive->hasFile(filename); +} + +byteArray CMinecraftApp::getArchiveFile(const wstring &filename) +{ + TexturePack *tPack = NULL; + Minecraft *pMinecraft = Minecraft::GetInstance(); + if(pMinecraft && pMinecraft->skins) tPack = pMinecraft->skins->getSelected(); + if(tPack && tPack->hasData() && tPack->getArchiveFile() && tPack->getArchiveFile()->hasFile(filename)) + { + return tPack->getArchiveFile()->getFile(filename); + } + else return m_mediaArchive->getFile(filename); +} + +// DLC + +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) +int CMinecraftApp::GetDLCInfoCount() +{ + return (int)DLCInfo.size(); +} +#elif defined _XBOX_ONE +int CMinecraftApp::GetDLCInfoTrialOffersCount() +{ + return 0; +} + +int CMinecraftApp::GetDLCInfoFullOffersCount() +{ + return (int)DLCInfo_Full.size(); +} +#else +int CMinecraftApp::GetDLCInfoTrialOffersCount() +{ + return (int)DLCInfo_Trial.size(); +} + +int CMinecraftApp::GetDLCInfoFullOffersCount() +{ + return (int)DLCInfo_Full.size(); +} +#endif + +int CMinecraftApp::GetDLCInfoTexturesOffersCount() +{ + return (int)DLCTextures_PackID.size(); +} + +// AUTOSAVE +void CMinecraftApp::SetAutosaveTimerTime(void) +{ +#if defined(_XBOX_ONE) || defined(__ORBIS__) + m_uiAutosaveTimer= GetTickCount()+1000*60; +#else + m_uiAutosaveTimer= GetTickCount()+GetGameSettings(ProfileManager.GetPrimaryPad(),eGameSetting_Autosave)*1000*60*15; +#endif +}// value x 15 to get mins, x60 for secs + +bool CMinecraftApp::AutosaveDue(void) +{ + return (GetTickCount()>m_uiAutosaveTimer); +} + +unsigned int CMinecraftApp::SecondsToAutosave() +{ + return (m_uiAutosaveTimer - GetTickCount() ) / 1000; +} + +void CMinecraftApp::SetTrialTimerStart(void) +{ + m_fTrialTimerStart=m_Time.fAppTime; mfTrialPausedTime=0.0f; +} + +float CMinecraftApp::getTrialTimer(void) +{ + return m_Time.fAppTime-m_fTrialTimerStart-mfTrialPausedTime; +} + +bool CMinecraftApp::IsLocalMultiplayerAvailable() +{ + DWORD connectedControllers = 0; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + if( InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i) ) ++connectedControllers; + } + + bool available = RenderManager.IsHiDef() && connectedControllers > 1; + +#ifdef __ORBIS__ + // Check for remote play + available = available && InputManager.IsLocalMultiplayerAvailable(); +#endif + + return available; + + // Found this in GameNetworkManager? + //#ifdef _DURANGO + // iOtherConnectedControllers = InputManager.GetConnectedGamepadCount(); + // if((InputManager.IsPadConnected(userIndex) || ProfileManager.IsSignedIn(userIndex))) + // { + // --iOtherConnectedControllers; + // } + //#else + // for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + // { + // if( (i!=userIndex) && (InputManager.IsPadConnected(i) || ProfileManager.IsSignedIn(i)) ) + // { + // iOtherConnectedControllers++; + // } + // } + //#endif +} + + +// 4J-PB - language and locale function + +void CMinecraftApp::getLocale(vector &vecWstrLocales) +{ + vector locales; + + DWORD dwSystemLanguage = XGetLanguage( ); + + // 4J-PB - restrict the 360 language until we're ready to have them in + +#ifdef _XBOX + switch(dwSystemLanguage) + { + case XC_LANGUAGE_FRENCH : + locales.push_back(eMCLang_frFR); + break; + case XC_LANGUAGE_ITALIAN : + locales.push_back(eMCLang_itIT); + break; + case XC_LANGUAGE_GERMAN : + locales.push_back(eMCLang_deDE); + break; + case XC_LANGUAGE_SPANISH : + locales.push_back(eMCLang_esES); + break; + case XC_LANGUAGE_PORTUGUESE : + if(XGetLocale()==XC_LOCALE_BRAZIL) + { + locales.push_back(eMCLang_ptBR); + } + locales.push_back(eMCLang_ptPT); + break; + case XC_LANGUAGE_JAPANESE : + locales.push_back(eMCLang_jaJP); + break; + case XC_LANGUAGE_KOREAN : + locales.push_back(eMCLang_koKR); + break; + case XC_LANGUAGE_TCHINESE : + locales.push_back(eMCLang_zhCHT); + break; + } +#else + switch(dwSystemLanguage) + { + + case XC_LANGUAGE_ENGLISH: + switch(XGetLocale()) + { + case XC_LOCALE_AUSTRALIA: + case XC_LOCALE_CANADA: + case XC_LOCALE_CZECH_REPUBLIC: + case XC_LOCALE_GREECE: + case XC_LOCALE_HONG_KONG: + case XC_LOCALE_HUNGARY: + case XC_LOCALE_INDIA: + case XC_LOCALE_IRELAND: + case XC_LOCALE_ISRAEL: + case XC_LOCALE_NEW_ZEALAND: + case XC_LOCALE_SAUDI_ARABIA: + case XC_LOCALE_SINGAPORE: + case XC_LOCALE_SLOVAK_REPUBLIC: + case XC_LOCALE_SOUTH_AFRICA: + case XC_LOCALE_UNITED_ARAB_EMIRATES: + case XC_LOCALE_GREAT_BRITAIN: + locales.push_back(eMCLang_enGB); + break; + default: //XC_LOCALE_UNITED_STATES + break; + } + break; + case XC_LANGUAGE_JAPANESE : + locales.push_back(eMCLang_jaJP); + break; + case XC_LANGUAGE_GERMAN : + switch(XGetLocale()) + { + case XC_LOCALE_AUSTRIA: + locales.push_back(eMCLang_deAT); + break; + case XC_LOCALE_SWITZERLAND: + locales.push_back(eMCLang_deCH); + break; + default:// XC_LOCALE_GERMANY: + break; + } + locales.push_back(eMCLang_deDE); + break; + case XC_LANGUAGE_FRENCH : + switch(XGetLocale()) + { + case XC_LOCALE_BELGIUM: + locales.push_back(eMCLang_frBE); + break; + case XC_LOCALE_CANADA: + locales.push_back(eMCLang_frCA); + break; + case XC_LOCALE_SWITZERLAND: + locales.push_back(eMCLang_frCH); + break; + default:// XC_LOCALE_FRANCE: + break; + } + locales.push_back(eMCLang_frFR); + break; + case XC_LANGUAGE_SPANISH : + switch(XGetLocale()) + { + case XC_LOCALE_MEXICO: + case XC_LOCALE_ARGENTINA: + case XC_LOCALE_CHILE: + case XC_LOCALE_COLOMBIA: + case XC_LOCALE_UNITED_STATES: + locales.push_back(eMCLang_esMX); + break; + default://XC_LOCALE_SPAIN + break; + } + locales.push_back(eMCLang_esES); + break; + case XC_LANGUAGE_ITALIAN : + locales.push_back(eMCLang_itIT); + break; + case XC_LANGUAGE_KOREAN : + locales.push_back(eMCLang_koKR); + break; + case XC_LANGUAGE_TCHINESE : + switch(XGetLocale()) + { + case XC_LOCALE_HONG_KONG: + locales.push_back(eMCLang_zhHK); + locales.push_back(eMCLang_zhTW); + break; + case XC_LOCALE_TAIWAN: + locales.push_back(eMCLang_zhTW); + locales.push_back(eMCLang_zhHK); + default: + break; + } + locales.push_back(eMCLang_zhCHT); + break; + case XC_LANGUAGE_PORTUGUESE : + if(XGetLocale()==XC_LOCALE_BRAZIL) + { + locales.push_back(eMCLang_ptBR); + } + locales.push_back(eMCLang_ptPT); + break; + case XC_LANGUAGE_POLISH : + locales.push_back(eMCLang_plPL); + break; + case XC_LANGUAGE_RUSSIAN : + locales.push_back(eMCLang_ruRU); + break; + case XC_LANGUAGE_SWEDISH : + locales.push_back(eMCLang_svSV); + locales.push_back(eMCLang_svSE); + break; + case XC_LANGUAGE_TURKISH : + locales.push_back(eMCLang_trTR); + break; + case XC_LANGUAGE_BNORWEGIAN : + locales.push_back(eMCLang_nbNO); + locales.push_back(eMCLang_noNO); + locales.push_back(eMCLang_nnNO); + break; + case XC_LANGUAGE_DUTCH : + switch(XGetLocale()) + { + case XC_LOCALE_BELGIUM: + locales.push_back(eMCLang_nlBE); + break; + default: + break; + } + locales.push_back(eMCLang_nlNL); + break; + case XC_LANGUAGE_SCHINESE : + switch(XGetLocale()) + { + case XC_LOCALE_SINGAPORE: + locales.push_back(eMCLang_zhSG); + break; + default: + break; + } + locales.push_back(eMCLang_zhCHS); + locales.push_back(eMCLang_zhCN); + break; + + +#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ || defined _DURANGO + case XC_LANGUAGE_DANISH: + locales.push_back(eMCLang_daDA); + locales.push_back(eMCLang_daDK); + break; + + case XC_LANGUAGE_LATINAMERICANSPANISH: + locales.push_back(eMCLang_laLAS); + locales.push_back(eMCLang_esES); + break; + + case XC_LANGUAGE_FINISH : + locales.push_back(eMCLang_fiFI); + break; + + case XC_LANGUAGE_CZECH : + locales.push_back(eMCLang_csCZ); + locales.push_back(eMCLang_enCZ); + break; + + case XC_LANGUAGE_SLOVAK : + locales.push_back(eMCLang_skSK); + locales.push_back(eMCLang_enSK); + break; + + case XC_LANGUAGE_GREEK : + locales.push_back(eMCLang_elEL); + locales.push_back(eMCLang_elGR); + locales.push_back(eMCLang_enGR); + locales.push_back(eMCLang_enGB); + break; +#endif + } +#endif + + locales.push_back(eMCLang_enUS); + locales.push_back(eMCLang_null); + + for (int i=0; i +#include "..\Common\Tutorial\TutorialEnum.h" + +#ifdef _XBOX +#include "..\Common\XUI\XUI_Helper.h" +#include "..\Common\XUI\XUI_HelpCredits.h" +#endif +#include "UI\UIStructs.h" + +#include "..\..\Minecraft.World\DisconnectPacket.h" +#include + +#include "..\StringTable.h" +#include "..\Common\DLC\DLCManager.h" +#include "..\Common\GameRules\ConsoleGameRulesConstants.h" +#include "..\Common\GameRules\GameRuleManager.h" +#include "..\SkinBox.h" +#include "..\ArchiveFile.h" + +typedef struct _JoinFromInviteData +{ + DWORD dwUserIndex; // dwUserIndex + DWORD dwLocalUsersMask; // dwUserMask + const INVITE_INFO *pInviteInfo; // pInviteInfo +} +JoinFromInviteData; + +class Player; +class Inventory; +class Level; +class FurnaceTileEntity; +class Container; +class DispenserTileEntity; +class SignTileEntity; +class BrewingStandTileEntity; +class LocalPlayer; +class DLCPack; +class LevelRuleset; +class ConsoleSchematicFile; +class Model; +class ModelPart; +class StringTable; +class Merchant; + +class CMinecraftAudio; + +class CMinecraftApp + +#ifdef _XBOX + : public CXuiModule +#endif +{ +private: + static int s_iHTMLFontSizesA[eHTMLSize_COUNT]; + +public: + + CMinecraftApp(); + + static const float fSafeZoneX; // 5% of 1280 + static const float fSafeZoneY; // 5% of 720 + + typedef std::vector VMEMFILES; + typedef std::vector VNOTIFICATIONS; + + // storing skin files + std::vector vSkinNames; + DLCManager m_dlcManager; + + // storing credits text from the DLC + std::vector m_vCreditText; // hold the credit text lines so we can avoid duplicating them + + + // In builds prior to TU5, the size of the GAME_SETTINGS struct was 204 bytes. We added a few new values to the internal struct in TU5, and even though we + // changed the size of the ucUnused array to be decreased by the size of the values we added, the packing of the struct has introduced some extra + // padding that resulted in the GAME_SETTINGS struct being 208 bytes. The knock-on effect from this was that all the stats, which come after the game settings + // in the profile data, we being read offset by 4 bytes. We need to ensure that the GAME_SETTINGS struct does not grow larger than 204 bytes or if we need it + // to then we need to rebuild the profile data completely and increase the profile version. There should be enough free space to grow larger for a few more updates + // as long as we take into account the padding issues and check that settings are still stored at the same positions when we read them + static const int GAME_SETTINGS_PROFILE_DATA_BYTES = 204; + +#ifdef _EXTENDED_ACHIEVEMENTS + /* 4J-JEV: + * We need more space in the profile data because of the new achievements and statistics + * necessary for the new expanded achievement set. + */ + static const int GAME_DEFINED_PROFILE_DATA_BYTES = 2*972; // per user +#else + static const int GAME_DEFINED_PROFILE_DATA_BYTES = 972; // per user +#endif + unsigned int uiGameDefinedDataChangedBitmask; + + void DebugPrintf(const char *szFormat, ...); + void DebugPrintfVerbose(bool bVerbose, const char *szFormat, ...); // Conditional printf + void DebugPrintf(int user, const char *szFormat, ...); + + static const int USER_NONE = 0; // disables printf + static const int USER_GENERAL = 1; + static const int USER_JV = 2; + static const int USER_MH = 3; + static const int USER_PB = 4; + static const int USER_RR = 5; + static const int USER_SR = 6; + static const int USER_UI = 7; // 4J Stu - This also makes it appear on the UI console + + void HandleButtonPresses(); + bool IntroRunning() { return m_bIntroRunning;} + void SetIntroRunning(bool bSet) {m_bIntroRunning=bSet;} +#ifdef _CONTENT_PACKAGE +#ifndef _FINAL_BUILD + bool PartnernetPasswordRunning() { return m_bPartnernetPasswordRunning;} + void SetPartnernetPasswordRunning(bool bSet) {m_bPartnernetPasswordRunning=bSet;} +#endif +#endif + + bool IsAppPaused(); + void SetAppPaused(bool val); + static int DisplaySavingMessage(LPVOID pParam,const C4JStorage::ESavingMessage eMsg, int iPad); + bool GetGameStarted() {return m_bGameStarted;} + void SetGameStarted(bool bVal) { if(bVal) DebugPrintf("SetGameStarted - true\n"); else DebugPrintf("SetGameStarted - false\n"); m_bGameStarted = bVal; m_bIsAppPaused = !bVal;} + int GetLocalPlayerCount(void); + bool LoadInventoryMenu(int iPad,shared_ptr player, bool bNavigateBack=false); + bool LoadCreativeMenu(int iPad,shared_ptr player,bool bNavigateBack=false); + bool LoadEnchantingMenu(int iPad,shared_ptr inventory, int x, int y, int z, Level *level); + bool LoadFurnaceMenu(int iPad,shared_ptr inventory, shared_ptr furnace); + bool LoadBrewingStandMenu(int iPad,shared_ptr inventory, shared_ptr brewingStand); + bool LoadContainerMenu(int iPad,shared_ptr inventory, shared_ptr container); + bool LoadTrapMenu(int iPad,shared_ptr inventory, shared_ptr trap); + bool LoadCrafting2x2Menu(int iPad,shared_ptr player); + bool LoadCrafting3x3Menu(int iPad,shared_ptr player, int x, int y, int z); + bool LoadSignEntryMenu(int iPad,shared_ptr sign); + bool LoadRepairingMenu(int iPad,shared_ptr inventory, Level *level, int x, int y, int z); + bool LoadTradingMenu(int iPad, shared_ptr inventory, shared_ptr trader, Level *level); + + bool GetTutorialMode() { return m_bTutorialMode;} + void SetTutorialMode(bool bSet) {m_bTutorialMode=bSet;} + + void SetSpecialTutorialCompletionFlag(int iPad, int index); + + static LPCWSTR GetString(int iID); + + eGameMode GetGameMode() { return m_eGameMode;} + void SetGameMode(eGameMode eMode) { m_eGameMode=eMode;} + + eXuiAction GetGlobalXuiAction() {return m_eGlobalXuiAction;} + void SetGlobalXuiAction(eXuiAction action) {m_eGlobalXuiAction=action;} + eXuiAction GetXuiAction(int iPad) {return m_eXuiAction[iPad];} + void SetAction(int iPad, eXuiAction action, LPVOID param = NULL); + void SetTMSAction(int iPad, eTMSAction action) {m_eTMSAction[iPad]=action; } + eTMSAction GetTMSAction(int iPad) {return m_eTMSAction[iPad];} + eXuiServerAction GetXuiServerAction(int iPad) {return m_eXuiServerAction[iPad];} + LPVOID GetXuiServerActionParam(int iPad) {return m_eXuiServerActionParam[iPad];} + void SetXuiServerAction(int iPad, eXuiServerAction action, LPVOID param = NULL) {m_eXuiServerAction[iPad]=action; m_eXuiServerActionParam[iPad] = param;} + eXuiServerAction GetGlobalXuiServerAction() {return m_eGlobalXuiServerAction;} + void SetGlobalXuiServerAction(eXuiServerAction action) {m_eGlobalXuiServerAction=action;} + + DisconnectPacket::eDisconnectReason GetDisconnectReason() { return m_disconnectReason; } + void SetDisconnectReason(DisconnectPacket::eDisconnectReason bVal) { m_disconnectReason = bVal; } + + bool GetChangingSessionType() { return m_bChangingSessionType; } + void SetChangingSessionType(bool bVal) { m_bChangingSessionType = bVal; } + + bool GetReallyChangingSessionType() { return m_bReallyChangingSessionType; } + void SetReallyChangingSessionType(bool bVal) { m_bReallyChangingSessionType = bVal; } + + + // 4J Stu - Added so that we can call this when a confirmation box is selected + static void SetActionConfirmed(LPVOID param); + void HandleXuiActions(void); + + // 4J Stu - Functions used for Minecon and other promo work + bool GetLoadSavesFromFolderEnabled() { return m_bLoadSavesFromFolderEnabled; } + void SetLoadSavesFromFolderEnabled(bool bVal) { m_bLoadSavesFromFolderEnabled = bVal; } + + // 4J Stu - Useful for debugging + bool GetWriteSavesToFolderEnabled() { return m_bWriteSavesToFolderEnabled; } + void SetWriteSavesToFolderEnabled(bool bVal) { m_bWriteSavesToFolderEnabled = bVal; } + bool GetMobsDontAttackEnabled() { return m_bMobsDontAttack; } + void SetMobsDontAttackEnabled(bool bVal) { m_bMobsDontAttack = bVal; } + bool GetUseDPadForDebug() { return m_bUseDPadForDebug; } + void SetUseDPadForDebug(bool bVal) { m_bUseDPadForDebug = bVal; } + bool GetMobsDontTickEnabled() { return m_bMobsDontTick; } + void SetMobsDontTickEnabled(bool bVal) { m_bMobsDontTick = bVal; } + + bool GetFreezePlayers() { return m_bFreezePlayers; } + void SetFreezePlayers(bool bVal) { m_bFreezePlayers = bVal; } + + // debug -0 show safe area + void ShowSafeArea(BOOL bShow) + { +#ifdef _XBOX + CXuiSceneBase::ShowSafeArea( bShow ); +#endif + } + // 4J-PB - to capture the social post screenshot + virtual void CaptureScreenshot(int iPad) {}; + //void GetPreviewImage(int iPad,XSOCIAL_PREVIEWIMAGE *preview); + + void InitGameSettings(); + static int OldProfileVersionCallback(LPVOID pParam,unsigned char *pucData, const unsigned short usVersion, const int iPad); + +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__ ) + static int DefaultOptionsCallback(LPVOID pParam,C4JStorage::PROFILESETTINGS *pSettings, const int iPad); + int SetDefaultOptions(C4JStorage::PROFILESETTINGS *pSettings,const int iPad,bool bWriteProfile=true); +#ifdef __ORBIS__ + static int OptionsDataCallback(LPVOID pParam,int iPad,unsigned short usVersion,C4JStorage::eOptionsCallback eStatus,int iBlocksRequired); + int GetOptionsBlocksRequired(int iPad); +#else + static int OptionsDataCallback(LPVOID pParam,int iPad,unsigned short usVersion,C4JStorage::eOptionsCallback eStatus); +#endif + + C4JStorage::eOptionsCallback GetOptionsCallbackStatus(int iPad); + + void SetOptionsCallbackStatus(int iPad, C4JStorage::eOptionsCallback eStatus); +#else + static int DefaultOptionsCallback(LPVOID pParam,C_4JProfile::PROFILESETTINGS *pSettings, const int iPad); + int SetDefaultOptions(C_4JProfile::PROFILESETTINGS *pSettings,const int iPad); +#endif + virtual void SetRichPresenceContext(int iPad, int contextId) = 0; + + + void SetGameSettings(int iPad,eGameSetting eVal,unsigned char ucVal); + unsigned char GetGameSettings(int iPad,eGameSetting eVal); + unsigned char GetGameSettings(eGameSetting eVal); // for the primary pad + void SetPlayerSkin(int iPad,const wstring &name); + void SetPlayerSkin(int iPad,DWORD dwSkinId); + void SetPlayerCape(int iPad,const wstring &name); + void SetPlayerCape(int iPad,DWORD dwCapeId); + void SetPlayerFavoriteSkin(int iPad, int iIndex,unsigned int uiSkinID); + unsigned int GetPlayerFavoriteSkin(int iPad,int iIndex); + unsigned char GetPlayerFavoriteSkinsPos(int iPad); + void SetPlayerFavoriteSkinsPos(int iPad,int iPos); + unsigned int GetPlayerFavoriteSkinsCount(int iPad); + void ValidateFavoriteSkins(int iPad); // check the DLC is available for the skins + + // Mash-up pack worlds hide/display + void HideMashupPackWorld(int iPad, unsigned int iMashupPackID); + void EnableMashupPackWorlds(int iPad); + unsigned int GetMashupPackWorlds(int iPad); + + // Minecraft language select + void SetMinecraftLanguage(int iPad, unsigned char ucLanguage); + unsigned char GetMinecraftLanguage(int iPad); + + + // 4J-PB - set a timer when the user navigates the quickselect, so we can bring the opacity back to defaults for a short time + unsigned int GetOpacityTimer(int iPad) { return m_uiOpacityCountDown[iPad]; } + void SetOpacityTimer(int iPad) { m_uiOpacityCountDown[iPad]=120; } // 6 seconds + void TickOpacityTimer(int iPad) { if(m_uiOpacityCountDown[iPad]>0) m_uiOpacityCountDown[iPad]--;} + +public: + wstring GetPlayerSkinName(int iPad); + DWORD GetPlayerSkinId(int iPad); + wstring GetPlayerCapeName(int iPad); + DWORD GetPlayerCapeId(int iPad); + DWORD GetAdditionalModelParts(int iPad); + void CheckGameSettingsChanged(bool bOverride5MinuteTimer=false, int iPad=XUSER_INDEX_ANY); + void ApplyGameSettingsChanged(int iPad); + void ClearGameSettingsChangedFlag(int iPad); + void ActionGameSettings(int iPad,eGameSetting eVal); + unsigned int GetGameSettingsDebugMask(int iPad=-1,bool bOverridePlayer=false); + void SetGameSettingsDebugMask(int iPad, unsigned int uiVal); + void ActionDebugMask(int iPad, bool bSetAllClear=false); + + // + bool IsLocalMultiplayerAvailable(); + + // for sign in change monitoring + static void SignInChangeCallback(LPVOID pParam, bool bVal, unsigned int uiSignInData); + static void ClearSignInChangeUsersMask(); + static int SignoutExitWorldThreadProc( void* lpParameter ); + static int PrimaryPlayerSignedOutReturned(void *pParam, int iPad, const C4JStorage::EMessageResult); + static int EthernetDisconnectReturned(void *pParam, int iPad, const C4JStorage::EMessageResult); + static void ProfileReadErrorCallback(void *pParam); + + // FATAL LOAD ERRORS + virtual void FatalLoadError(); + + // Notifications from the game listener to be passed to the qnet listener + static void NotificationsCallback(LPVOID pParam,DWORD dwNotification, unsigned int uiParam); + + // for the ethernet being disconnected + static void LiveLinkChangeCallback(LPVOID pParam,BOOL bConnected); + bool GetLiveLinkRequired() {return m_bLiveLinkRequired;} + void SetLiveLinkRequired(bool required) {m_bLiveLinkRequired=required;} + + static void UpsellReturnedCallback(LPVOID pParam, eUpsellType type, eUpsellResponse result, int iUserData); + +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ + static int NowDisplayFullVersionPurchase(void *pParam, bool bContinue, int iPad); + static int MustSignInFullVersionPurchaseReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); +#endif +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ + static int MustSignInFullVersionPurchaseReturnedExitTrial(void *pParam,int iPad,C4JStorage::EMessageResult result); +#endif + +#ifdef _DEBUG_MENUS_ENABLED + bool DebugSettingsOn() { return m_bDebugOptions;} +#else + bool DebugSettingsOn() { return false;} +#endif + void SetDebugSequence(const char *pchSeq); + static int DebugInputCallback(LPVOID pParam); + //bool UploadFileToGlobalStorage(int iQuadrant, C4JStorage::eGlobalStorage eStorageFacility, wstring *wsFile ); + + // Installed DLC + bool StartInstallDLCProcess(int iPad); + static int DLCInstalledCallback(LPVOID pParam,int iOfferC,int iPad); + void HandleDLCLicenseChange(); + static int DLCMountedCallback(LPVOID pParam,int iPad,DWORD dwErr,DWORD dwLicenceMask); + void MountNextDLC(int iPad); + //static int DLCReadCallback(LPVOID pParam,C4JStorage::DLC_FILE_DETAILS *pDLCData); + void HandleDLC(DLCPack *pack); + bool DLCInstallPending() {return m_bDLCInstallPending;} + bool DLCInstallProcessCompleted() {return m_bDLCInstallProcessCompleted;} + void ClearDLCInstalled() { m_bDLCInstallProcessCompleted=false;} + static int MarketplaceCountsCallback(LPVOID pParam,C4JStorage::DLC_TMS_DETAILS *,int iPad); + + bool AlreadySeenCreditText(const wstring &wstemp); + + void ClearNewDLCAvailable(void) { m_bNewDLCAvailable=false; m_bSeenNewDLCTip=true;} + bool GetNewDLCAvailable() { return m_bNewDLCAvailable;} + void DisplayNewDLCTipAgain() { m_bSeenNewDLCTip=false;} + bool DisplayNewDLCTip() { if(!m_bSeenNewDLCTip) { m_bSeenNewDLCTip=true; return true;} else return false;} + + // functions to store launch data, and to exit the game - required due to possibly being on a demo disc + virtual void StoreLaunchData(); + virtual void ExitGame(); + + bool isXuidNotch(PlayerUID xuid); + bool isXuidDeadmau5(PlayerUID xuid); + + void AddMemoryTextureFile(const wstring &wName, PBYTE pbData, DWORD dwBytes); + void RemoveMemoryTextureFile(const wstring &wName); + void GetMemFileDetails(const wstring &wName,PBYTE *ppbData,DWORD *pdwBytes); + bool IsFileInMemoryTextures(const wstring &wName); + + // Texture Pack Data files (icon, banner, comparison shot & text) + void AddMemoryTPDFile(int iConfig,PBYTE pbData,DWORD dwBytes); + void RemoveMemoryTPDFile(int iConfig); + bool IsFileInTPD(int iConfig); + void GetTPD(int iConfig,PBYTE *ppbData,DWORD *pdwBytes); + int GetTPDSize() {return m_MEM_TPD.size();} +#ifndef __PS3__ + int GetTPConfigVal(WCHAR *pwchDataFile); +#endif + + bool DefaultCapeExists(); + //void InstallDefaultCape(); // attempt to install the default cape once per game launch + + // invites + //void ProcessInvite(JoinFromInviteData *pJoinData); + void ProcessInvite(DWORD dwUserIndex, DWORD dwLocalUsersMask, const INVITE_INFO * pInviteInfo); + + // Add credits for DLC installed + void AddCreditText(LPCWSTR lpStr); + +private: + PlayerUID m_xuidNotch; +#ifdef _DURANGO + unordered_map m_GTS_Files; +#else + unordered_map m_GTS_Files; +#endif + + // for storing memory textures - player skin + unordered_map m_MEM_Files; + // for storing texture pack data files + unordered_map m_MEM_TPD; + CRITICAL_SECTION csMemFilesLock; // For locking access to the above map + CRITICAL_SECTION csMemTPDLock; // For locking access to the above map + + VNOTIFICATIONS m_vNotifications; + +public: + // launch data + BYTE* m_pLaunchData; + DWORD m_dwLaunchDataSize; + +public: + // BAN LIST + void AddLevelToBannedLevelList(int iPad,PlayerUID xuid, char *pszLevelName, bool bWriteToTMS); + bool IsInBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName); + void RemoveLevelFromBannedLevelList(int iPad, PlayerUID xuid, char *pszLevelName); + void InvalidateBannedList(int iPad); + void SetUniqueMapName(char *pszUniqueMapName); + char *GetUniqueMapName(void); +#ifdef _XBOX_ONE + void AddLevelToBannedLevelList(int iPad, PBANNEDLISTDATA pBannedListData, bool bWriteToTMS); +#endif + + +public: + bool GetResourcesLoaded() {return m_bResourcesLoaded;} + void SetResourcesLoaded(bool bVal) {m_bResourcesLoaded=bVal;} + +public: + bool m_bGameStarted; + bool m_bIntroRunning; + bool m_bTutorialMode; + bool m_bIsAppPaused; + + bool m_bChangingSessionType; + bool m_bReallyChangingSessionType; + + bool m_bDisplayFullVersionPurchase; // for after signing in during the trial, and trying to unlock full version on an upsell + + void loadMediaArchive(); + void loadStringTable(); + +protected: + ArchiveFile *m_mediaArchive; + StringTable *m_stringTable; + +public: + int getArchiveFileSize(const wstring &filename); + bool hasArchiveFile(const wstring &filename); + byteArray getArchiveFile(const wstring &filename); + +private: + + static int BannedLevelDialogReturned(void *pParam,int iPad,const C4JStorage::EMessageResult); + static int TexturePackDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + VBANNEDLIST *m_vBannedListA[XUSER_MAX_COUNT]; + + void HandleButtonPresses(int iPad); + + bool m_bResourcesLoaded; + + // Global string table for this application. + //CXuiStringTable StringTable; + + + // Container scene for some menu + +// CXuiScene debugContainerScene; + + + //bool m_bSplitScreenEnabled; + + +#ifdef _CONTENT_PACKAGE +#ifndef _FINAL_BUILD + bool m_bPartnernetPasswordRunning; +#endif +#endif + + eGameMode m_eGameMode; // single or multiplayer + + static unsigned int m_uiLastSignInData; + + // We've got sizeof(GAME_SETTINGS) bytes reserved at the start of the gamedefined data per player for settings + GAME_SETTINGS *GameSettingsA[XUSER_MAX_COUNT]; + + // For promo work + bool m_bLoadSavesFromFolderEnabled; + + // For debugging + bool m_bWriteSavesToFolderEnabled; + bool m_bMobsDontAttack; + bool m_bUseDPadForDebug; + bool m_bMobsDontTick; + bool m_bFreezePlayers; + + // 4J : WESTY : For taking screen shots. + //bool m_bInterfaceRenderingOff; + //bool m_bHandRenderingOff; + + DisconnectPacket::eDisconnectReason m_disconnectReason; + +public: + virtual void RunFrame() {}; + + + + static const DWORD m_dwOfferID = 0x00000001; + +// timer + void InitTime(); + void UpdateTime(); + + // trial timer + void SetTrialTimerStart(void); + float getTrialTimer(void); + + // notifications from the game for qnet + VNOTIFICATIONS *GetNotifications() {return &m_vNotifications;} + +private: + + + // To avoid problems with threads being kicked off from xuis that alter things that may be in progress within the run_middle, + // we'll action these at the end of the game loop + eXuiAction m_eXuiAction[XUSER_MAX_COUNT]; + eTMSAction m_eTMSAction[XUSER_MAX_COUNT]; + LPVOID m_eXuiActionParam[XUSER_MAX_COUNT]; + eXuiAction m_eGlobalXuiAction; + eXuiServerAction m_eXuiServerAction[XUSER_MAX_COUNT]; + LPVOID m_eXuiServerActionParam[XUSER_MAX_COUNT]; + eXuiServerAction m_eGlobalXuiServerAction; + + bool m_bLiveLinkRequired; + + static int UnlockFullExitReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int UnlockFullSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int UnlockFullInviteReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int TrialOverReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitAndJoinFromInvite(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitAndJoinFromInviteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitAndJoinFromInviteAndSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int ExitAndJoinFromInviteDeclineSaveReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int FatalErrorDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int WarningTrialTexturePackReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); + + JoinFromInviteData m_InviteData; + bool m_bDebugOptions; // toggle debug things on or off + + // Trial timer + float m_fTrialTimerStart,mfTrialPausedTime; + typedef struct TimeInfo + { + LARGE_INTEGER qwTime; + LARGE_INTEGER qwAppTime; + + float fAppTime; + float fElapsedTime; + float fSecsPerTick; + } TIMEINFO; + + TimeInfo m_Time; + +protected: + static const int MAX_TIPS_GAMETIP = 50; + static const int MAX_TIPS_TRIVIATIP = 20; + static TIPSTRUCT m_GameTipA[MAX_TIPS_GAMETIP]; + static TIPSTRUCT m_TriviaTipA[MAX_TIPS_TRIVIATIP]; + static Random *TipRandom; +public: + void InitialiseTips(); + UINT GetNextTip(); + int GetHTMLColour(eMinecraftColour colour); + int GetHTMLColor(eMinecraftColour colour) { return GetHTMLColour(colour); } + int GetHTMLFontSize(EHTMLFontSize size); + wstring FormatHTMLString(int iPad, const wstring &desc, int shadowColour = 0xFFFFFFFF); + wstring GetActionReplacement(int iPad, unsigned char ucAction); + wstring GetVKReplacement(unsigned int uiVKey); + wstring GetIconReplacement(unsigned int uiIcon); + + float getAppTime() { return m_Time.fAppTime; } + void UpdateTrialPausedTimer() { mfTrialPausedTime+= m_Time.fElapsedTime;} + + static int RemoteSaveThreadProc( void* lpParameter ); + static void ExitGameFromRemoteSave( LPVOID lpParameter ); + static int ExitGameFromRemoteSaveDialogReturned(void *pParam,int iPad,C4JStorage::EMessageResult result); +private: + UINT m_TipIDA[MAX_TIPS_GAMETIP+MAX_TIPS_TRIVIATIP]; + UINT m_uiCurrentTip; + static int TipsSortFunction(const void* a, const void* b); + + // XML +public: + + // Hold a vector of terrain feature positions + void AddTerrainFeaturePosition(_eTerrainFeatureType,int,int); + void ClearTerrainFeaturePosition(); + _eTerrainFeatureType IsTerrainFeature(int x,int z); + bool GetTerrainFeaturePosition(_eTerrainFeatureType eType, int *pX, int *pZ); + std::vector m_vTerrainFeatures; + + static HRESULT RegisterMojangData(WCHAR *, PlayerUID, WCHAR *, WCHAR *); + MOJANG_DATA *GetMojangDataForXuid(PlayerUID xuid); + static HRESULT RegisterConfigValues(WCHAR *pType, int iValue); + +#if defined(__PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + HRESULT RegisterDLCData(char *pchDLCName, unsigned int uiSortIndex, char *pchImageURL); + bool GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal); + DLC_INFO *GetDLCInfoForTrialOfferID(ULONGLONG ullOfferID_Trial); + DLC_INFO *GetDLCInfoForFullOfferID(ULONGLONG ullOfferID_Full); +#elif defined(_XBOX_ONE) + static HRESULT RegisterDLCData(eDLCContentType, WCHAR *, WCHAR *, WCHAR *, WCHAR *, int, unsigned int); + //bool GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,WCHAR *pwchProductId); + bool GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,wstring &wsProductId); + DLC_INFO *GetDLCInfoForFullOfferID(WCHAR *pwchProductId); + DLC_INFO *GetDLCInfoForProductName(WCHAR *pwchProductName); +#else + static HRESULT RegisterDLCData(WCHAR *, WCHAR *, int, __uint64, __uint64, WCHAR *, unsigned int, int, WCHAR *pDataFile); + bool GetDLCFullOfferIDForSkinID(const wstring &FirstSkin,ULONGLONG *pullVal); + DLC_INFO *GetDLCInfoForTrialOfferID(ULONGLONG ullOfferID_Trial); + DLC_INFO *GetDLCInfoForFullOfferID(ULONGLONG ullOfferID_Full); +#endif + + unsigned int GetDLCCreditsCount(); + SCreditTextItemDef * GetDLCCredits(int iIndex); + +// TMS + void ReadDLCFileFromTMS(int iPad,eTMSAction action, bool bCallback=false); + void ReadXuidsFileFromTMS(int iPad,eTMSAction action,bool bCallback=false); + + // images for save thumbnail/social post + virtual void CaptureSaveThumbnail() =0; + virtual void GetSaveThumbnail(PBYTE*,DWORD*)=0; + virtual void ReleaseSaveThumbnail()=0; + virtual void GetScreenshot(int iPad,PBYTE *pbData,DWORD *pdwSize)=0; + + virtual void ReadBannedList(int iPad, eTMSAction action=(eTMSAction)0, bool bCallback=false)=0; + +private: + + std::vector vDLCCredits; + +#if defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) + static unordered_map MojangData; + static unordered_map DLCTextures_PackID; // for mash-up packs & texture packs + static unordered_map DLCInfo; + static unordered_map DLCInfo_SkinName; // skin name, full offer id +#elif defined(_DURANGO) + static unordered_map MojangData; + static unordered_map DLCTextures_PackID; // for mash-up packs & texture packs + //static unordered_map DLCInfo_Trial; // full offerid, dlc_info + static unordered_map DLCInfo_Full; // full offerid, dlc_info + static unordered_map DLCInfo_SkinName; // skin name, full offer id +#else + static unordered_map MojangData; + static unordered_map DLCTextures_PackID; // for mash-up packs & texture packs + static unordered_map DLCInfo_Trial; // full offerid, dlc_info + static unordered_map DLCInfo_Full; // full offerid, dlc_info + static unordered_map DLCInfo_SkinName; // skin name, full offer id +#endif +// bool m_bRead_TMS_XUIDS_XML; // track whether we have already read the TMS xuids.xml file +// bool m_bRead_TMS_DLCINFO_XML; // track whether we have already read the TMS DLC.xml file + + bool m_bDefaultCapeInstallAttempted; // have we attempted to install the default cape from tms + + //bool m_bwasHidingGui; // 4J Stu - Removed 1.8.2 bug fix (TU6) as not needed + bool m_bDLCInstallProcessCompleted; + bool m_bDLCInstallPending; + int m_iTotalDLC; + int m_iTotalDLCInstalled; + +public: + // 4J Stu - We need to be able to detect when a guest player signs in or out causing other guest players to change their xuid + // The simplest way to do this is to check if their guest number has changed, so store the last known one here + // 4J Stu - Now storing the whole XUSER_SIGNIN_INFO so we can detect xuid changes + XUSER_SIGNIN_INFO m_currentSigninInfo[XUSER_MAX_COUNT]; + + //void OverrideFontRenderer(bool set, bool immediate = true); +// void ToggleFontRenderer() { OverrideFontRenderer(!m_bFontRendererOverridden,false); } + BANNEDLIST BannedListA[XUSER_MAX_COUNT]; + +private: +// XUI_FontRenderer *m_fontRenderer; +// bool m_bFontRendererOverridden; +// bool m_bOverrideFontRenderer; + + + bool m_bRead_BannedListA[XUSER_MAX_COUNT]; + char m_pszUniqueMapName[14]; + bool m_BanListCheck[XUSER_MAX_COUNT]; + +public: + void SetBanListCheck(int iPad,bool bVal) {m_BanListCheck[iPad]=bVal;} + bool GetBanListCheck(int iPad) { return m_BanListCheck[iPad];} +// AUTOSAVE +public: + void SetAutosaveTimerTime(void); + bool AutosaveDue(void); + unsigned int SecondsToAutosave(); +private: + unsigned int m_uiAutosaveTimer; + unsigned int m_uiOpacityCountDown[XUSER_MAX_COUNT]; + + // DLC + bool m_bNewDLCAvailable; + bool m_bSeenNewDLCTip; + + // Host options +private: + unsigned int m_uiGameHostSettings; + static unsigned char m_szPNG[8]; + + unsigned int FromBigEndian(unsigned int uiValue); + +public: + + + void SetGameHostOption(eGameHostOption eVal,unsigned int uiVal); + void SetGameHostOption(unsigned int &uiHostSettings, eGameHostOption eVal,unsigned int uiVal); + unsigned int GetGameHostOption(eGameHostOption eVal); + unsigned int GetGameHostOption(unsigned int uiHostSettings, eGameHostOption eVal); + + void SetResetNether(bool bResetNether) {m_bResetNether=bResetNether;} + bool GetResetNether() {return m_bResetNether;} + bool CanRecordStatsAndAchievements(); + + // World seed from png image + void GetImageTextData(PBYTE pbImageData, DWORD dwImageBytes,unsigned char *pszSeed,unsigned int &uiHostOptions,bool &bHostOptionsRead,DWORD &uiTexturePack); + unsigned int CreateImageTextData(PBYTE bTextMetadata, __int64 seed, bool hasSeed, unsigned int uiHostOptions, unsigned int uiTexturePackId); + + // Game rules + GameRuleManager m_gameRules; + +public: + void processSchematics(LevelChunk *levelChunk); + void processSchematicsLighting(LevelChunk *levelChunk); + void loadDefaultGameRules(); + vector *getLevelGenerators() { return m_gameRules.getLevelGenerators(); } + void setLevelGenerationOptions(LevelGenerationOptions *levelGen); + LevelRuleset *getGameRuleDefinitions() { return m_gameRules.getGameRuleDefinitions(); } + LevelGenerationOptions *getLevelGenerationOptions() { return m_gameRules.getLevelGenerationOptions(); } + LPCWSTR GetGameRulesString(const wstring &key); + +private: + BYTE m_playerColours[MINECRAFT_NET_MAX_PLAYERS]; // An array of QNet small-id's + unsigned int m_playerGamePrivileges[MINECRAFT_NET_MAX_PLAYERS]; + +public: + void UpdatePlayerInfo(BYTE networkSmallId, SHORT playerColourIndex, unsigned int playerGamePrivileges); + short GetPlayerColour(BYTE networkSmallId); + unsigned int GetPlayerPrivileges(BYTE networkSmallId); + + wstring getEntityName(eINSTANCEOF type); + + + + unsigned int AddDLCRequest(eDLCMarketplaceType eContentType, bool bPromote=false); + bool RetrieveNextDLCContent(); + bool CheckTMSDLCCanStop(); + static int DLCOffersReturned(void *pParam, int iOfferC, DWORD dwType, int iPad); + DWORD GetDLCContentType(eDLCContentType eType) { return m_dwContentTypeA[eType];} + eDLCContentType Find_eDLCContentType(DWORD dwType); + int GetDLCOffersCount() { return m_iDLCOfferC;} + bool DLCContentRetrieved(eDLCMarketplaceType eType); + void TickDLCOffersRetrieved(); + void ClearAndResetDLCDownloadQueue(); + bool RetrieveNextTMSPPContent(); + void TickTMSPPFilesRetrieved(); + void ClearTMSPPFilesRetrieved(); + unsigned int AddTMSPPFileTypeRequest(eDLCContentType eType, bool bPromote=false); + int GetDLCInfoTexturesOffersCount(); +#if defined( __PS3__) || defined(__ORBIS__) || defined(__PSVITA__) + DLC_INFO *GetDLCInfo(int iIndex); + DLC_INFO *GetDLCInfo(char *); + DLC_INFO *GetDLCInfoFromTPackID(int iTPID); + bool GetDLCNameForPackID(const int iPackID,char **ppchKeyID); + char * GetDLCInfoTextures(int iIndex); + int GetDLCInfoCount(); +#else + +#ifdef _XBOX_ONE + static int TMSPPFileReturned(LPVOID pParam,int iPad,int iUserData,LPVOID, WCHAR *wchFilename); + unordered_map *GetDLCInfo(); +#else + static int TMSPPFileReturned(LPVOID pParam,int iPad,int iUserData,C4JStorage::PTMSPP_FILEDATA pFileData, LPCSTR szFilename); +#endif + DLC_INFO *GetDLCInfoTrialOffer(int iIndex); + DLC_INFO *GetDLCInfoFullOffer(int iIndex); + + int GetDLCInfoTrialOffersCount(); + int GetDLCInfoFullOffersCount(); +#ifdef _XBOX_ONE + bool GetDLCFullOfferIDForPackID(const int iPackID,wstring &wsProductId); + wstring GetDLCInfoTexturesFullOffer(int iIndex); + +#else + bool GetDLCFullOfferIDForPackID(const int iPackID,ULONGLONG *pullVal); + ULONGLONG GetDLCInfoTexturesFullOffer(int iIndex); +#endif +#endif + + void SetCorruptSaveDeleted(bool bVal) {m_bCorruptSaveDeleted=bVal;} + bool GetCorruptSaveDeleted(void) {return m_bCorruptSaveDeleted;} + + void EnterSaveNotificationSection(); + void LeaveSaveNotificationSection(); +private: + CRITICAL_SECTION m_saveNotificationCriticalSection; + int m_saveNotificationDepth; + // Download Status + + //Request current_download; + vector m_DLCDownloadQueue; + vector m_TMSPPDownloadQueue; + static DWORD m_dwContentTypeA[e_Marketplace_MAX]; + int m_iDLCOfferC; + bool m_bAllDLCContentRetrieved; + bool m_bAllTMSContentRetrieved; + bool m_bTickTMSDLCFiles; + CRITICAL_SECTION csDLCDownloadQueue; + CRITICAL_SECTION csTMSPPDownloadQueue; + CRITICAL_SECTION csAdditionalModelParts; + CRITICAL_SECTION csAdditionalSkinBoxes; + CRITICAL_SECTION csAnimOverrideBitmask; + bool m_bCorruptSaveDeleted; + + DWORD m_dwAdditionalModelParts[XUSER_MAX_COUNT]; + + BYTE *m_pBannedListFileBuffer; + DWORD m_dwBannedListFileSize; + +public: + DWORD m_dwDLCFileSize; + BYTE *m_pDLCFileBuffer; + +// static int CallbackReadXuidsFileFromTMS(LPVOID lpParam, WCHAR *wchFilename, int iPad, bool bResult, int iAction); +// static int CallbackDLCFileFromTMS(LPVOID lpParam, WCHAR *wchFilename, int iPad, bool bResult, int iAction); +// static int CallbackBannedListFileFromTMS(LPVOID lpParam, WCHAR *wchFilename, int iPad, bool bResult, int iAction); + + // Storing additional model parts per skin texture + void SetAdditionalSkinBoxes(DWORD dwSkinID, SKIN_BOX *SkinBoxA, DWORD dwSkinBoxC); + vector * SetAdditionalSkinBoxes(DWORD dwSkinID, vector *pvSkinBoxA); + vector *GetAdditionalModelParts(DWORD dwSkinID); + vector *GetAdditionalSkinBoxes(DWORD dwSkinID); + void SetAnimOverrideBitmask(DWORD dwSkinID,unsigned int uiAnimOverrideBitmask); + unsigned int GetAnimOverrideBitmask(DWORD dwSkinID); + + static DWORD getSkinIdFromPath(const wstring &skin); + static wstring getSkinPathFromId(DWORD skinId); + + virtual int LoadLocalTMSFile(WCHAR *wchTMSFile)=0; + virtual int LoadLocalTMSFile(WCHAR *wchTMSFile, eFileExtensionType eExt)=0; + virtual void FreeLocalTMSFiles(eTMSFileType eType)=0; + virtual int GetLocalTMSFileIndex(WCHAR *wchTMSFile,bool bFilenameIncludesExtension,eFileExtensionType eEXT)=0; + + virtual bool GetTMSGlobalFileListRead() { return true;} + virtual bool GetTMSDLCInfoRead() { return true;} + virtual bool GetTMSXUIDsFileRead() { return true;} + + bool GetBanListRead(int iPad) { return m_bRead_BannedListA[iPad];} + void SetBanListRead(int iPad,bool bVal) { m_bRead_BannedListA[iPad]=bVal;} + void ClearBanList(int iPad) { BannedListA[iPad].pBannedList=NULL;BannedListA[iPad].dwBytes=0;} + + DWORD GetRequiredTexturePackID() {return m_dwRequiredTexturePackID;} + void SetRequiredTexturePackID(DWORD dwID) {m_dwRequiredTexturePackID=dwID;} + + virtual void GetFileFromTPD(eTPDFileType eType,PBYTE pbData,DWORD dwBytes,PBYTE *ppbData,DWORD *pdwBytes ) {*ppbData = NULL; *pdwBytes = 0;} + + //XTITLE_DEPLOYMENT_TYPE getDeploymentType() { return m_titleDeploymentType; } + +private: + // vector of additional skin model parts, indexed by the skin texture id + unordered_map *> m_AdditionalModelParts; + unordered_map *> m_AdditionalSkinBoxes; + unordered_map m_AnimOverrides; + + + bool m_bResetNether; + DWORD m_dwRequiredTexturePackID; +#ifdef _XBOX_ONE + vector m_vTMSPPData; +#endif + +#if ( defined __PS3__ || defined __ORBIS__ || defined _DURANGO || defined __PSVITA__) + C4JStorage::eOptionsCallback m_eOptionsStatusA[XUSER_MAX_COUNT]; + +#ifdef __ORBIS__ + int m_eOptionsBlocksRequiredA[XUSER_MAX_COUNT]; +#endif +#endif + + + // 4J-PB - language and locale functions +public: + + void LocaleAndLanguageInit(); + void getLocale(vector &vecWstrLocales); + DWORD get_eMCLang(WCHAR *pwchLocale); + DWORD get_xcLang(WCHAR *pwchLocale); + + void SetTickTMSDLCFiles(bool bVal); + + wstring getFilePath(DWORD packId, wstring filename, bool bAddDataFolder); + +private: + unordered_mapm_localeA; + unordered_mapm_eMCLangA; + unordered_mapm_xcLangA; + wstring getRootPath(DWORD packId, bool allowOverride, bool bAddDataFolder); +public: + +#ifdef _XBOX +// bool m_bTransferSavesToXboxOne; +// unsigned int m_uiTransferSlotC; + +#elif defined (__PS3__) + +#elif defined _DURANGO + +#elif defined _WINDOWS64 + //CMinecraftAudio audio; +#else // PS4 + +#endif + +#ifdef _XBOX_ONE +public: + void SetReachedMainMenu(); + bool HasReachedMainMenu(); +private: + bool m_hasReachedMainMenu; +#endif +}; + +//singleton +//extern CMinecraftApp app; diff --git a/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp new file mode 100644 index 0000000..eabc140 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.cpp @@ -0,0 +1,70 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.enchantment.h" +#include "AddEnchantmentRuleDefinition.h" + +AddEnchantmentRuleDefinition::AddEnchantmentRuleDefinition() +{ + m_enchantmentId = m_enchantmentLevel = 0; +} + +void AddEnchantmentRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 2); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_enchantmentId); + dos->writeUTF( _toString( m_enchantmentId ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_enchantmentLevel); + dos->writeUTF( _toString( m_enchantmentLevel ) ); +} + +void AddEnchantmentRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"enchantmentId") == 0) + { + int value = _fromString(attributeValue); + if(value < 0) value = 0; + if(value >= 256) value = 255; + m_enchantmentId = value; + app.DebugPrintf("AddEnchantmentRuleDefinition: Adding parameter enchantmentId=%d\n",m_enchantmentId); + } + else if(attributeName.compare(L"enchantmentLevel") == 0) + { + int value = _fromString(attributeValue); + if(value < 0) value = 0; + m_enchantmentLevel = value; + app.DebugPrintf("AddEnchantmentRuleDefinition: Adding parameter enchantmentLevel=%d\n",m_enchantmentLevel); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool AddEnchantmentRuleDefinition::enchantItem(shared_ptr item) +{ + bool enchanted = false; + if (item != NULL) + { + // 4J-JEV: Ripped code from enchantmenthelpers + // Maybe we want to add an addEnchantment method to EnchantmentHelpers + if (item->id == Item::enchantedBook_Id) + { + Item::enchantedBook->addEnchantment( item, new EnchantmentInstance(m_enchantmentId, m_enchantmentLevel) ); + } + else if (item->isEnchantable()) + { + Enchantment *e = Enchantment::enchantments[m_enchantmentId]; + + if(e != NULL && e->category->canEnchant(item->getItem())) + { + int level = min(e->getMaxLevel(), m_enchantmentLevel); + item->enchant(e, m_enchantmentLevel); + enchanted = true; + } + } + } + return enchanted; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h new file mode 100644 index 0000000..3beece1 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddEnchantmentRuleDefinition.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class ItemInstance; + +class AddEnchantmentRuleDefinition : public GameRuleDefinition +{ +private: + int m_enchantmentId; + int m_enchantmentLevel; + +public: + AddEnchantmentRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_AddEnchantment; } + + virtual void writeAttributes(DataOutputStream *, UINT numAttrs); + + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool enchantItem(shared_ptr item); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp new file mode 100644 index 0000000..0d14884 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.cpp @@ -0,0 +1,127 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "AddItemRuleDefinition.h" +#include "AddEnchantmentRuleDefinition.h" + +AddItemRuleDefinition::AddItemRuleDefinition() +{ + m_itemId = m_quantity = m_auxValue = m_dataTag = 0; + m_slot = -1; +} + +void AddItemRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_itemId); + dos->writeUTF( _toString( m_itemId ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_quantity); + dos->writeUTF( _toString( m_quantity ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_auxValue); + dos->writeUTF( _toString( m_auxValue ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_dataTag); + dos->writeUTF( _toString( m_dataTag ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_slot); + dos->writeUTF( _toString( m_slot ) ); +} + +void AddItemRuleDefinition::getChildren(vector *children) +{ + GameRuleDefinition::getChildren( children ); + for (AUTO_VAR(it, m_enchantments.begin()); it != m_enchantments.end(); it++) + children->push_back( *it ); +} + +GameRuleDefinition *AddItemRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_AddEnchantment) + { + rule = new AddEnchantmentRuleDefinition(); + m_enchantments.push_back((AddEnchantmentRuleDefinition *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + //wprintf(L"AddItemRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void AddItemRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"itemId") == 0) + { + int value = _fromString(attributeValue); + m_itemId = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter itemId=%d\n",m_itemId); + } + else if(attributeName.compare(L"quantity") == 0) + { + int value = _fromString(attributeValue); + m_quantity = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter quantity=%d\n",m_quantity); + } + else if(attributeName.compare(L"auxValue") == 0) + { + int value = _fromString(attributeValue); + m_auxValue = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter auxValue=%d\n",m_auxValue); + } + else if(attributeName.compare(L"dataTag") == 0) + { + int value = _fromString(attributeValue); + m_dataTag = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter dataTag=%d\n",m_dataTag); + } + else if(attributeName.compare(L"slot") == 0) + { + int value = _fromString(attributeValue); + m_slot = value; + //app.DebugPrintf(2,"AddItemRuleDefinition: Adding parameter slot=%d\n",m_slot); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool AddItemRuleDefinition::addItemToContainer(shared_ptr container, int slotId) +{ + bool added = false; + if(Item::items[m_itemId] != NULL) + { + int quantity = min(m_quantity, Item::items[m_itemId]->getMaxStackSize()); + shared_ptr newItem = shared_ptr(new ItemInstance(m_itemId,quantity,m_auxValue) ); + newItem->set4JData(m_dataTag); + + for(AUTO_VAR(it, m_enchantments.begin()); it != m_enchantments.end(); ++it) + { + (*it)->enchantItem(newItem); + } + + if(m_slot >= 0 && m_slot < container->getContainerSize() ) + { + container->setItem( m_slot, newItem ); + added = true; + } + else if(slotId >= 0 && slotId < container->getContainerSize() ) + { + container->setItem( slotId, newItem ); + added = true; + } + else if(dynamic_pointer_cast(container) != NULL) + { + added = dynamic_pointer_cast(container)->add(newItem); + } + } + return added; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h new file mode 100644 index 0000000..602f2d8 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/AddItemRuleDefinition.h @@ -0,0 +1,30 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class Container; +class AddEnchantmentRuleDefinition; + +class AddItemRuleDefinition : public GameRuleDefinition +{ +private: + int m_itemId; + int m_quantity; + int m_auxValue; + int m_dataTag; + int m_slot; + vector m_enchantments; + +public: + AddItemRuleDefinition(); + + virtual void writeAttributes(DataOutputStream *, UINT numAttributes); + virtual void getChildren(vector *children); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_AddItem; } + + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool addItemToContainer(shared_ptr container, int slotId); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp new file mode 100644 index 0000000..aa4a8fb --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.cpp @@ -0,0 +1,249 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.dimension.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "ApplySchematicRuleDefinition.h" +#include "LevelGenerationOptions.h" +#include "ConsoleSchematicFile.h" + +ApplySchematicRuleDefinition::ApplySchematicRuleDefinition(LevelGenerationOptions *levelGenOptions) +{ + m_levelGenOptions = levelGenOptions; + m_location = Vec3::newPermanent(0,0,0); + m_locationBox = NULL; + m_totalBlocksChanged = 0; + m_totalBlocksChangedLighting = 0; + m_rotation = ConsoleSchematicFile::eSchematicRot_0; + m_completed = false; + m_dimension = 0; + m_schematic = NULL; +} + +ApplySchematicRuleDefinition::~ApplySchematicRuleDefinition() +{ + app.DebugPrintf("Deleting ApplySchematicRuleDefinition.\n"); + if(!m_completed) m_levelGenOptions->releaseSchematicFile(m_schematicName); + m_schematic = NULL; + delete m_location; +} + +void ApplySchematicRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_filename); + dos->writeUTF(m_schematicName); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_location->x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_location->y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_location->z)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_rot); + + switch (m_rotation) + { + case ConsoleSchematicFile::eSchematicRot_0: dos->writeUTF(_toString( 0 )); break; + case ConsoleSchematicFile::eSchematicRot_90: dos->writeUTF(_toString( 90 )); break; + case ConsoleSchematicFile::eSchematicRot_180: dos->writeUTF(_toString( 180 )); break; + case ConsoleSchematicFile::eSchematicRot_270: dos->writeUTF(_toString( 270 )); break; + } +} + +void ApplySchematicRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"filename") == 0) + { + m_schematicName = attributeValue; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter filename=%s\n",m_schematicName.c_str()); + + if(!m_schematicName.empty()) + { + if(m_schematicName.substr( m_schematicName.length() - 4, m_schematicName.length()).compare(L".sch") != 0) + { + m_schematicName.append(L".sch"); + } + m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + } + } + else if(attributeName.compare(L"x") == 0) + { + m_location->x = _fromString(attributeValue); + if( ((int)abs(m_location->x))%2 != 0) m_location->x -=1; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter x=%f\n",m_location->x); + } + else if(attributeName.compare(L"y") == 0) + { + m_location->y = _fromString(attributeValue); + if( ((int)abs(m_location->y))%2 != 0) m_location->y -= 1; + if(m_location->y < 0) m_location->y = 0; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter y=%f\n",m_location->y); + } + else if(attributeName.compare(L"z") == 0) + { + m_location->z = _fromString(attributeValue); + if(((int)abs(m_location->z))%2 != 0) m_location->z -= 1; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter z=%f\n",m_location->z); + } + else if(attributeName.compare(L"rot") == 0) + { + int degrees = _fromString(attributeValue); + + while(degrees < 0) degrees += 360; + while(degrees >= 360) degrees -= 360; + float quad = degrees/90; + degrees = (int)(quad + 0.5f); + switch(degrees) + { + case 1: + m_rotation = ConsoleSchematicFile::eSchematicRot_90; + break; + case 2: + m_rotation = ConsoleSchematicFile::eSchematicRot_180; + break; + case 3: + case 4: + m_rotation = ConsoleSchematicFile::eSchematicRot_270; + break; + case 0: + default: + m_rotation = ConsoleSchematicFile::eSchematicRot_0; + break; + }; + + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter rot=%d\n",m_rotation); + } + else if(attributeName.compare(L"dim") == 0) + { + m_dimension = _fromString(attributeValue); + if(m_dimension > 1 || m_dimension < -1) m_dimension = 0; + //app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter dimension=%d\n",m_dimension); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +void ApplySchematicRuleDefinition::updateLocationBox() +{ + if(m_schematic == NULL) m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + + m_locationBox = AABB::newPermanent(0,0,0,0,0,0); + + m_locationBox->x0 = m_location->x; + m_locationBox->y0 = m_location->y; + m_locationBox->z0 = m_location->z; + + m_locationBox->y1 = m_location->y + m_schematic->getYSize(); + + switch(m_rotation) + { + case ConsoleSchematicFile::eSchematicRot_90: + case ConsoleSchematicFile::eSchematicRot_270: + m_locationBox->x1 = m_location->x + m_schematic->getZSize(); + m_locationBox->z1 = m_location->z + m_schematic->getXSize(); + break; + case ConsoleSchematicFile::eSchematicRot_0: + case ConsoleSchematicFile::eSchematicRot_180: + default: + m_locationBox->x1 = m_location->x + m_schematic->getXSize(); + m_locationBox->z1 = m_location->z + m_schematic->getZSize(); + break; + }; +} + +void ApplySchematicRuleDefinition::processSchematic(AABB *chunkBox, LevelChunk *chunk) +{ + if( m_completed ) return; + if(chunk->level->dimension->id != m_dimension) return; + + PIXBeginNamedEvent(0, "Processing ApplySchematicRuleDefinition"); + if(m_schematic == NULL) m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + + if(m_locationBox == NULL) updateLocationBox(); + if(chunkBox->intersects( m_locationBox )) + { + m_locationBox->y1 = min((double)Level::maxBuildHeight, m_locationBox->y1 ); + +#ifdef _DEBUG + app.DebugPrintf("Applying schematic %ls to chunk (%d,%d)\n",m_schematicName.c_str(),chunk->x, chunk->z); +#endif + PIXBeginNamedEvent(0,"Applying blocks and data"); + m_totalBlocksChanged += m_schematic->applyBlocksAndData(chunk, chunkBox, m_locationBox, m_rotation); + PIXEndNamedEvent(); + + // Add the tileEntities + PIXBeginNamedEvent(0,"Applying tile entities"); + m_schematic->applyTileEntities(chunk, chunkBox, m_locationBox, m_rotation); + PIXEndNamedEvent(); + + // TODO This does not take into account things that go outside the bounds of the world + int targetBlocks = (m_locationBox->x1 - m_locationBox->x0) + * (m_locationBox->y1 - m_locationBox->y0) + * (m_locationBox->z1 - m_locationBox->z0); + if( (m_totalBlocksChanged == targetBlocks) && (m_totalBlocksChangedLighting == targetBlocks) ) + { + m_completed = true; + //m_levelGenOptions->releaseSchematicFile(m_schematicName); + //m_schematic = NULL; + } + } + PIXEndNamedEvent(); +} + +void ApplySchematicRuleDefinition::processSchematicLighting(AABB *chunkBox, LevelChunk *chunk) +{ + if( m_completed ) return; + if(chunk->level->dimension->id != m_dimension) return; + + PIXBeginNamedEvent(0, "Processing ApplySchematicRuleDefinition (lighting)"); + if(m_schematic == NULL) m_schematic = m_levelGenOptions->getSchematicFile(m_schematicName); + + if(m_locationBox == NULL) updateLocationBox(); + if(chunkBox->intersects( m_locationBox )) + { + m_locationBox->y1 = min((double)Level::maxBuildHeight, m_locationBox->y1 ); + +#ifdef _DEBUG + app.DebugPrintf("Applying schematic %ls to chunk (%d,%d)\n",m_schematicName.c_str(),chunk->x, chunk->z); +#endif + PIXBeginNamedEvent(0,"Patching lighting"); + m_totalBlocksChangedLighting += m_schematic->applyLighting(chunk, chunkBox, m_locationBox, m_rotation); + PIXEndNamedEvent(); + + // TODO This does not take into account things that go outside the bounds of the world + int targetBlocks = (m_locationBox->x1 - m_locationBox->x0) + * (m_locationBox->y1 - m_locationBox->y0) + * (m_locationBox->z1 - m_locationBox->z0); + if( (m_totalBlocksChanged == targetBlocks) && (m_totalBlocksChangedLighting == targetBlocks) ) + { + m_completed = true; + //m_levelGenOptions->releaseSchematicFile(m_schematicName); + //m_schematic = NULL; + } + } + PIXEndNamedEvent(); +} + +bool ApplySchematicRuleDefinition::checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1) +{ + if( m_locationBox == NULL ) updateLocationBox(); + return m_locationBox->intersects(x0,y0,z0,x1,y1,z1); +} + +int ApplySchematicRuleDefinition::getMinY() +{ + if( m_locationBox == NULL ) updateLocationBox(); + return m_locationBox->y0; +} + +void ApplySchematicRuleDefinition::reset() +{ + m_totalBlocksChanged = 0; + m_totalBlocksChangedLighting = 0; + m_completed = false; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h new file mode 100644 index 0000000..21c42de --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ApplySchematicRuleDefinition.h @@ -0,0 +1,51 @@ +#pragma once +#include "GameRuleDefinition.h" +#include "ConsoleSchematicFile.h" + +class AABB; +class Vec3; +class LevelChunk; +class LevelGenerationOptions; +class GRFObject; + +class ApplySchematicRuleDefinition : public GameRuleDefinition +{ +private: + LevelGenerationOptions *m_levelGenOptions; + wstring m_schematicName; + ConsoleSchematicFile *m_schematic; + Vec3 *m_location; + AABB *m_locationBox; + ConsoleSchematicFile::ESchematicRotation m_rotation; + int m_dimension; + + __int64 m_totalBlocksChanged; + __int64 m_totalBlocksChangedLighting; + bool m_completed; + + void updateLocationBox(); +public: + ApplySchematicRuleDefinition(LevelGenerationOptions *levelGenOptions); + ~ApplySchematicRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_ApplySchematic; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + void processSchematic(AABB *chunkBox, LevelChunk *chunk); + void processSchematicLighting(AABB *chunkBox, LevelChunk *chunk); + + bool checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1); + int getMinY(); + + bool isComplete() { return m_completed; } + + wstring getSchematicName() { return m_schematicName; } + + /** 4J-JEV: + * This GameRuleDefinition contains limited game state. + * Reset any state to how it should be before a new game. + */ + void reset(); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/BiomeOverride.cpp b/Minecraft.Client/Common/GameRules/BiomeOverride.cpp new file mode 100644 index 0000000..22cc0c7 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/BiomeOverride.cpp @@ -0,0 +1,59 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "BiomeOverride.h" + +BiomeOverride::BiomeOverride() +{ + m_tile = 0; + m_topTile = 0; + m_biomeId = 0; +} + +void BiomeOverride::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_biomeId); + dos->writeUTF(_toString(m_biomeId)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_tileId); + dos->writeUTF(_toString(m_tile)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_topTileId); + dos->writeUTF(_toString(m_topTile)); +} + +void BiomeOverride::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"tileId") == 0) + { + int value = _fromString(attributeValue); + m_tile = value; + app.DebugPrintf("BiomeOverride: Adding parameter tileId=%d\n",m_tile); + } + else if(attributeName.compare(L"topTileId") == 0) + { + int value = _fromString(attributeValue); + m_topTile = value; + app.DebugPrintf("BiomeOverride: Adding parameter topTileId=%d\n",m_topTile); + } + else if(attributeName.compare(L"biomeId") == 0) + { + int value = _fromString(attributeValue); + m_biomeId = value; + app.DebugPrintf("BiomeOverride: Adding parameter biomeId=%d\n",m_biomeId); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool BiomeOverride::isBiome(int id) +{ + return m_biomeId == id; +} + +void BiomeOverride::getTileValues(BYTE &tile, BYTE &topTile) +{ + if(m_tile != 0) tile = (BYTE)m_tile; + if(m_topTile != 0) topTile = (BYTE)m_topTile; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/BiomeOverride.h b/Minecraft.Client/Common/GameRules/BiomeOverride.h new file mode 100644 index 0000000..5ad9263 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/BiomeOverride.h @@ -0,0 +1,23 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" + +class BiomeOverride : public GameRuleDefinition +{ +private: + BYTE m_topTile; + BYTE m_tile; + int m_biomeId; + +public: + BiomeOverride(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_BiomeOverride; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool isBiome(int id); + void getTileValues(BYTE &tile, BYTE &topTile); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp new file mode 100644 index 0000000..66abefb --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.cpp @@ -0,0 +1,117 @@ +#include "stdafx.h" +#include "..\..\WstringLookup.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "CollectItemRuleDefinition.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "..\..\..\Minecraft.World\Connection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" + +CollectItemRuleDefinition::CollectItemRuleDefinition() +{ + m_itemId = 0; + m_auxValue = 0; + m_quantity = 0; +} + +CollectItemRuleDefinition::~CollectItemRuleDefinition() +{ +} + +void CollectItemRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_itemId); + dos->writeUTF( _toString( m_itemId ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_auxValue); + dos->writeUTF( _toString( m_auxValue ) ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_quantity); + dos->writeUTF( _toString( m_quantity ) ); +} + +void CollectItemRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"itemId") == 0) + { + m_itemId = _fromString(attributeValue); + app.DebugPrintf("CollectItemRule: Adding parameter itemId=%d\n",m_itemId); + } + else if(attributeName.compare(L"auxValue") == 0) + { + m_auxValue = _fromString(attributeValue); + app.DebugPrintf("CollectItemRule: Adding parameter m_auxValue=%d\n",m_auxValue); + } + else if(attributeName.compare(L"quantity") == 0) + { + m_quantity = _fromString(attributeValue); + app.DebugPrintf("CollectItemRule: Adding parameter m_quantity=%d\n",m_quantity); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +int CollectItemRuleDefinition::getGoal() +{ + return m_quantity; +} + +int CollectItemRuleDefinition::getProgress(GameRule *rule) +{ + GameRule::ValueType value = rule->getParameter(L"iQuantity"); + return value.i; +} + +void CollectItemRuleDefinition::populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule) +{ + GameRule::ValueType value; + value.i = 0; + rule->setParameter(L"iQuantity",value); + + GameRuleDefinition::populateGameRule(type, rule); +} + +bool CollectItemRuleDefinition::onCollectItem(GameRule *rule, shared_ptr item) +{ + bool statusChanged = false; + if(item != NULL && item->id == m_itemId && item->getAuxValue() == m_auxValue && item->get4JData() == m_4JDataValue) + { + if(!getComplete(rule)) + { + GameRule::ValueType value = rule->getParameter(L"iQuantity"); + int quantityCollected = (value.i += item->count); + rule->setParameter(L"iQuantity",value); + + statusChanged = true; + + if(quantityCollected >= m_quantity) + { + setComplete(rule, true); + app.DebugPrintf("Completed CollectItemRule with info - itemId:%d, auxValue:%d, quantity:%d, dataTag:%d\n", m_itemId,m_auxValue,m_quantity,m_4JDataValue); + + if(rule->getConnection() != NULL) + { + rule->getConnection()->send( shared_ptr( new UpdateGameRuleProgressPacket(getActionType(), this->m_descriptionId, m_itemId, m_auxValue, this->m_4JDataValue,NULL,0))); + } + } + } + } + return statusChanged; +} + +wstring CollectItemRuleDefinition::generateXml(shared_ptr item) +{ + // 4J Stu - This should be kept in sync with the GameRulesDefinition.xsd + wstring xml = L""; + if(item != NULL) + { + xml = L"(item->id) + L"\" quantity=\"SET\" descriptionName=\"OPTIONAL\" promptName=\"OPTIONAL\""; + if(item->getAuxValue() != 0) xml += L" auxValue=\"" + _toString(item->getAuxValue()) + L"\""; + if(item->get4JData() != 0) xml += L" dataTag=\"" + _toString(item->get4JData()) + L"\""; + xml += L"/>\n"; + } + return xml; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h new file mode 100644 index 0000000..5ee6f4c --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CollectItemRuleDefinition.h @@ -0,0 +1,40 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class Pos; +class UseTileRuleDefinition; +class ItemInstance; + +class CollectItemRuleDefinition : public GameRuleDefinition +{ +private: + // These values should map directly to the xsd definition for this Rule + int m_itemId; + unsigned char m_auxValue; + int m_quantity; + +public: + CollectItemRuleDefinition(); + ~CollectItemRuleDefinition(); + + ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_CollectItemRule; } + + virtual void writeAttributes(DataOutputStream *, UINT numAttributes); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual int getGoal(); + virtual int getProgress(GameRule *rule); + + virtual int getIcon() { return m_itemId; } + virtual int getAuxValue() { return m_auxValue; } + + void populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule); + + bool onCollectItem(GameRule *rule, shared_ptr item); + + static wstring generateXml(shared_ptr item); + +private: + //static wstring generateXml(CollectItemRuleDefinition *ruleDef); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp new file mode 100644 index 0000000..adaf70c --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.cpp @@ -0,0 +1,66 @@ +#include "stdafx.h" +#include "CompleteAllRuleDefinition.h" +#include "ConsoleGameRules.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Connection.h" +#include "..\..\..\Minecraft.World\net.minecraft.network.packet.h" + +void CompleteAllRuleDefinition::getChildren(vector *children) +{ + CompoundGameRuleDefinition::getChildren(children); +} + +bool CompleteAllRuleDefinition::onUseTile(GameRule *rule, int tileId, int x, int y, int z) +{ + bool statusChanged = CompoundGameRuleDefinition::onUseTile(rule,tileId,x,y,z); + if(statusChanged) updateStatus(rule); + return statusChanged; +} + +bool CompleteAllRuleDefinition::onCollectItem(GameRule *rule, shared_ptr item) +{ + bool statusChanged = CompoundGameRuleDefinition::onCollectItem(rule,item); + if(statusChanged) updateStatus(rule); + return statusChanged; +} + +void CompleteAllRuleDefinition::updateStatus(GameRule *rule) +{ + int goal = 0; + int progress = 0; + for(AUTO_VAR(it, rule->m_parameters.begin()); it != rule->m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + goal += it->second.gr->getGameRuleDefinition()->getGoal(); + progress += it->second.gr->getGameRuleDefinition()->getProgress(it->second.gr); + } + } + if(rule->getConnection() != NULL) + { + PacketData data; + data.goal = goal; + data.progress = progress; + + int icon = -1; + int auxValue = 0; + + if(m_lastRuleStatusChanged != NULL) + { + icon = m_lastRuleStatusChanged->getIcon(); + auxValue = m_lastRuleStatusChanged->getAuxValue(); + m_lastRuleStatusChanged = NULL; + } + rule->getConnection()->send( shared_ptr( new UpdateGameRuleProgressPacket(getActionType(), this->m_descriptionId,icon, auxValue, 0,&data,sizeof(PacketData)))); + } + app.DebugPrintf("Updated CompleteAllRule - Completed %d of %d\n", progress, goal); +} + +wstring CompleteAllRuleDefinition::generateDescriptionString(const wstring &description, void *data, int dataLength) +{ + PacketData *values = (PacketData *)data; + wstring newDesc = description; + newDesc = replaceAll(newDesc,L"{*progress*}",_toString(values->progress)); + newDesc = replaceAll(newDesc,L"{*goal*}",_toString(values->goal)); + return newDesc; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h new file mode 100644 index 0000000..b2cb884 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompleteAllRuleDefinition.h @@ -0,0 +1,26 @@ +#pragma once + +#include "CompoundGameRuleDefinition.h" + +class CompleteAllRuleDefinition : public CompoundGameRuleDefinition +{ +private: + typedef struct _packetData + { + int goal; + int progress; + } PacketData; + +public: + ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_CompleteAllRule; } + + virtual void getChildren(vector *children); + + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z); + virtual bool onCollectItem(GameRule *rule, shared_ptr item); + + static wstring generateDescriptionString(const wstring &description, void *data, int dataLength); + +private: + void updateStatus(GameRule *rule); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp new file mode 100644 index 0000000..0481a54 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.cpp @@ -0,0 +1,118 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" +#include "CompoundGameRuleDefinition.h" +#include "ConsoleGameRules.h" + +CompoundGameRuleDefinition::CompoundGameRuleDefinition() +{ + m_lastRuleStatusChanged = NULL; +} + +CompoundGameRuleDefinition::~CompoundGameRuleDefinition() +{ + for(AUTO_VAR(it, m_children.begin()); it != m_children.end(); ++it) + { + delete (*it); + } +} + +void CompoundGameRuleDefinition::getChildren(vector *children) +{ + GameRuleDefinition::getChildren(children); + for (AUTO_VAR(it, m_children.begin()); it != m_children.end(); it++) + children->push_back(*it); +} + +GameRuleDefinition *CompoundGameRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_CompleteAllRule) + { + rule = new CompleteAllRuleDefinition(); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_CollectItemRule) + { + rule = new CollectItemRuleDefinition(); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_UseTileRule) + { + rule = new UseTileRuleDefinition(); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_UpdatePlayerRule) + { + rule = new UpdatePlayerRuleDefinition(); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"CompoundGameRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + if(rule != NULL) m_children.push_back(rule); + return rule; +} + +void CompoundGameRuleDefinition::populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule) +{ + GameRule *newRule = NULL; + int i = 0; + for(AUTO_VAR(it, m_children.begin()); it != m_children.end(); ++it) + { + newRule = new GameRule(*it, rule->getConnection() ); + (*it)->populateGameRule(type,newRule); + + GameRule::ValueType value; + value.gr = newRule; + value.isPointer = true; + + // Somehow add the newRule to the current rule + rule->setParameter(L"rule" + _toString(i),value); + ++i; + } + GameRuleDefinition::populateGameRule(type, rule); +} + +bool CompoundGameRuleDefinition::onUseTile(GameRule *rule, int tileId, int x, int y, int z) +{ + bool statusChanged = false; + for(AUTO_VAR(it, rule->m_parameters.begin()); it != rule->m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + bool changed = it->second.gr->getGameRuleDefinition()->onUseTile(it->second.gr,tileId,x,y,z); + if(!statusChanged && changed) + { + m_lastRuleStatusChanged = it->second.gr->getGameRuleDefinition(); + statusChanged = true; + } + } + } + return statusChanged; +} + +bool CompoundGameRuleDefinition::onCollectItem(GameRule *rule, shared_ptr item) +{ + bool statusChanged = false; + for(AUTO_VAR(it, rule->m_parameters.begin()); it != rule->m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + bool changed = it->second.gr->getGameRuleDefinition()->onCollectItem(it->second.gr,item); + if(!statusChanged && changed) + { + m_lastRuleStatusChanged = it->second.gr->getGameRuleDefinition(); + statusChanged = true; + } + } + } + return statusChanged; +} + +void CompoundGameRuleDefinition::postProcessPlayer(shared_ptr player) +{ + for(AUTO_VAR(it, m_children.begin()); it != m_children.end(); ++it) + { + (*it)->postProcessPlayer(player); + } +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h new file mode 100644 index 0000000..bfedfd0 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/CompoundGameRuleDefinition.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class CompoundGameRuleDefinition : public GameRuleDefinition +{ +protected: + vector m_children; +protected: + GameRuleDefinition *m_lastRuleStatusChanged; +public: + CompoundGameRuleDefinition(); + virtual ~CompoundGameRuleDefinition(); + + virtual void getChildren(vector *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual void populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule); + + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z); + virtual bool onCollectItem(GameRule *rule, shared_ptr item); + virtual void postProcessPlayer(shared_ptr player); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGameRules.h b/Minecraft.Client/Common/GameRules/ConsoleGameRules.h new file mode 100644 index 0000000..41c5e55 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGameRules.h @@ -0,0 +1,32 @@ +#pragma once +#include "ConsoleGameRulesConstants.h" + +#include "GameRuleManager.h" + +#include "GameRule.h" + +#include "GameRuleDefinition.h" + +#include "LevelRuleset.h" +#include "NamedAreaRuleDefinition.h" + +#include "CollectItemRuleDefinition.h" +#include "CompleteAllRuleDefinition.h" +#include "CompoundGameRuleDefinition.h" +#include "UseTileRuleDefinition.h" +#include "UpdatePlayerRuleDefinition.h" +#include "AddItemRuleDefinition.h" +#include "AddEnchantmentRuleDefinition.h" + +#include "LevelGenerationOptions.h" +#include "ApplySchematicRuleDefinition.h" +#include "ConsoleGenerateStructure.h" +#include "ConsoleGenerateStructureAction.h" +#include "XboxStructureActionGenerateBox.h" +#include "XboxStructureActionPlaceBlock.h" +#include "XboxStructureActionPlaceContainer.h" +#include "XboxStructureActionPlaceSpawner.h" +#include "BiomeOverride.h" +#include "StartFeature.h" + +#include "GameRulesInstance.h" diff --git a/Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h b/Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h new file mode 100644 index 0000000..a7111f0 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGameRulesConstants.h @@ -0,0 +1,119 @@ +#pragma once + +//#include " + +class ConsoleGameRules +{ +public: + enum EGameRuleType + { + eGameRuleType_Invalid = -1, + eGameRuleType_Root = 0, // This is the top level rule that defines a game mode, this is used to generate data for new players + + eGameRuleType_LevelGenerationOptions, + eGameRuleType_ApplySchematic, + eGameRuleType_GenerateStructure, + eGameRuleType_GenerateBox, + eGameRuleType_PlaceBlock, + eGameRuleType_PlaceContainer, + eGameRuleType_PlaceSpawner, + eGameRuleType_BiomeOverride, + eGameRuleType_StartFeature, + + eGameRuleType_AddItem, + eGameRuleType_AddEnchantment, + + eGameRuleType_LevelRules, + eGameRuleType_NamedArea, + + eGameRuleType_UseTileRule, + eGameRuleType_CollectItemRule, + eGameRuleType_CompleteAllRule, + eGameRuleType_UpdatePlayerRule, + + eGameRuleType_Count + }; + + enum EGameRuleAttr + { + eGameRuleAttr_Invalid = -1, + + eGameRuleAttr_descriptionName = 0, + eGameRuleAttr_promptName, + eGameRuleAttr_dataTag, + + eGameRuleAttr_enchantmentId, + eGameRuleAttr_enchantmentLevel, + + eGameRuleAttr_itemId, + eGameRuleAttr_quantity, + eGameRuleAttr_auxValue, + eGameRuleAttr_slot, + + eGameRuleAttr_name, + + eGameRuleAttr_food, + eGameRuleAttr_health, + + eGameRuleAttr_tileId, + eGameRuleAttr_useCoords, + + eGameRuleAttr_seed, + eGameRuleAttr_flatworld, + + eGameRuleAttr_filename, + eGameRuleAttr_rot, + + eGameRuleAttr_data, + eGameRuleAttr_block, + eGameRuleAttr_entity, + + eGameRuleAttr_facing, + + eGameRuleAttr_edgeTile, + eGameRuleAttr_fillTile, + eGameRuleAttr_skipAir, + + eGameRuleAttr_x, + eGameRuleAttr_x0, + eGameRuleAttr_x1, + + eGameRuleAttr_y, + eGameRuleAttr_y0, + eGameRuleAttr_y1, + + eGameRuleAttr_z, + eGameRuleAttr_z0, + eGameRuleAttr_z1, + + eGameRuleAttr_chunkX, + eGameRuleAttr_chunkZ, + + eGameRuleAttr_yRot, + + eGameRuleAttr_spawnX, + eGameRuleAttr_spawnY, + eGameRuleAttr_spawnZ, + + eGameRuleAttr_orientation, + eGameRuleAttr_dimension, + + eGameRuleAttr_topTileId, + eGameRuleAttr_biomeId, + + eGameRuleAttr_feature, + + eGameRuleAttr_Count + }; + + static void write(DataOutputStream *dos, ConsoleGameRules::EGameRuleType eType) + { + dos->writeInt(eType); + } + + static void write(DataOutputStream *dos, ConsoleGameRules::EGameRuleAttr eAttr) + { + dos->writeInt( eGameRuleType_Count + eAttr ); + } + +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp new file mode 100644 index 0000000..0476b0e --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.cpp @@ -0,0 +1,181 @@ +#include "stdafx.h" +#include "ConsoleGenerateStructure.h" +#include "ConsoleGameRules.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.dimension.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.h" + +ConsoleGenerateStructure::ConsoleGenerateStructure() : StructurePiece(0) +{ + m_x = m_y = m_z = 0; + boundingBox = NULL; + orientation = Direction::NORTH; + m_dimension = 0; +} + +void ConsoleGenerateStructure::getChildren(vector *children) +{ + GameRuleDefinition::getChildren(children); + + for(AUTO_VAR(it, m_actions.begin()); it != m_actions.end(); it++) + children->push_back( *it ); +} + +GameRuleDefinition *ConsoleGenerateStructure::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_GenerateBox) + { + rule = new XboxStructureActionGenerateBox(); + m_actions.push_back((XboxStructureActionGenerateBox *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_PlaceBlock) + { + rule = new XboxStructureActionPlaceBlock(); + m_actions.push_back((XboxStructureActionPlaceBlock *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_PlaceContainer) + { + rule = new XboxStructureActionPlaceContainer(); + m_actions.push_back((XboxStructureActionPlaceContainer *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_PlaceSpawner) + { + rule = new XboxStructureActionPlaceSpawner(); + m_actions.push_back((XboxStructureActionPlaceSpawner *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"ConsoleGenerateStructure: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void ConsoleGenerateStructure::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_z)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_orientation); + dos->writeUTF(_toString(orientation)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_dimension); + dos->writeUTF(_toString(m_dimension)); +} + +void ConsoleGenerateStructure::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"x") == 0) + { + int value = _fromString(attributeValue); + m_x = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter x=%d\n",m_x); + } + else if(attributeName.compare(L"y") == 0) + { + int value = _fromString(attributeValue); + m_y = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter y=%d\n",m_y); + } + else if(attributeName.compare(L"z") == 0) + { + int value = _fromString(attributeValue); + m_z = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter z=%d\n",m_z); + } + else if(attributeName.compare(L"orientation") == 0) + { + int value = _fromString(attributeValue); + orientation = value; + app.DebugPrintf("ConsoleGenerateStructure: Adding parameter orientation=%d\n",orientation); + } + else if(attributeName.compare(L"dim") == 0) + { + m_dimension = _fromString(attributeValue); + if(m_dimension > 1 || m_dimension < -1) m_dimension = 0; + app.DebugPrintf("ApplySchematicRuleDefinition: Adding parameter dimension=%d\n",m_dimension); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +BoundingBox* ConsoleGenerateStructure::getBoundingBox() +{ + if(boundingBox == NULL) + { + // Find the max bounds + int maxX, maxY, maxZ; + maxX = maxY = maxZ = 1; + for(AUTO_VAR(it, m_actions.begin()); it != m_actions.end(); ++it) + { + ConsoleGenerateStructureAction *action = *it; + maxX = max(maxX,action->getEndX()); + maxY = max(maxY,action->getEndY()); + maxZ = max(maxZ,action->getEndZ()); + } + + boundingBox = new BoundingBox(m_x, m_y, m_z, m_x + maxX, m_y + maxY, m_z + maxZ); + } + return boundingBox; +} + +bool ConsoleGenerateStructure::postProcess(Level *level, Random *random, BoundingBox *chunkBB) +{ + if(level->dimension->id != m_dimension) return false; + + for(AUTO_VAR(it, m_actions.begin()); it != m_actions.end(); ++it) + { + ConsoleGenerateStructureAction *action = *it; + + switch(action->getActionType()) + { + case ConsoleGameRules::eGameRuleType_GenerateBox: + { + XboxStructureActionGenerateBox *genBox = (XboxStructureActionGenerateBox *)action; + genBox->generateBoxInLevel(this,level,chunkBB); + } + break; + case ConsoleGameRules::eGameRuleType_PlaceBlock: + { + XboxStructureActionPlaceBlock *pPlaceBlock = (XboxStructureActionPlaceBlock *)action; + pPlaceBlock->placeBlockInLevel(this,level,chunkBB); + } + break; + case ConsoleGameRules::eGameRuleType_PlaceContainer: + { + XboxStructureActionPlaceContainer *pPlaceContainer = (XboxStructureActionPlaceContainer *)action; + pPlaceContainer->placeContainerInLevel(this,level,chunkBB); + } + break; + case ConsoleGameRules::eGameRuleType_PlaceSpawner: + { + XboxStructureActionPlaceSpawner *pPlaceSpawner = (XboxStructureActionPlaceSpawner *)action; + pPlaceSpawner->placeSpawnerInLevel(this,level,chunkBB); + } + break; + }; + } + + return false; +} + +bool ConsoleGenerateStructure::checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1) +{ + return getBoundingBox()->intersects(x0,y0,z0,x1,y1,z1); +} + +int ConsoleGenerateStructure::getMinY() +{ + return getBoundingBox()->y0; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h new file mode 100644 index 0000000..5b97b10 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructure.h @@ -0,0 +1,38 @@ +#pragma once +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\StructurePiece.h" + +class Level; +class Random; +class BoundingBox; +class ConsoleGenerateStructureAction; +class XboxStructureActionPlaceContainer; +class GRFObject; + +class ConsoleGenerateStructure : public GameRuleDefinition, public StructurePiece +{ +private: + int m_x, m_y, m_z; + vector m_actions; + int m_dimension; +public: + ConsoleGenerateStructure(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_GenerateStructure; } + + virtual void getChildren(vector *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + // StructurePiece + virtual BoundingBox *getBoundingBox(); + virtual bool postProcess(Level *level, Random *random, BoundingBox *chunkBB); + + void createContainer(XboxStructureActionPlaceContainer *action, Level *level, BoundingBox *chunkBB); + + bool checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1); + + virtual int getMinY(); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h new file mode 100644 index 0000000..14eb2fd --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleGenerateStructureAction.h @@ -0,0 +1,11 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class ConsoleGenerateStructureAction : public GameRuleDefinition +{ +public: + virtual int getEndX() = 0; + virtual int getEndY() = 0; + virtual int getEndZ() = 0; +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp new file mode 100644 index 0000000..4a4e27b --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.cpp @@ -0,0 +1,1020 @@ +#include "stdafx.h" +#include +#include "..\..\..\Minecraft.World\com.mojang.nbt.h" +#include "..\..\..\Minecraft.World\System.h" +#include "ConsoleSchematicFile.h" +#include "..\..\..\Minecraft.World\InputOutputStream.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.item.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" +#include "..\..\..\Minecraft.World\compression.h" + +ConsoleSchematicFile::ConsoleSchematicFile() +{ + m_xSize = m_ySize = m_zSize = 0; + m_refCount = 1; + m_data.data = NULL; +} + +ConsoleSchematicFile::~ConsoleSchematicFile() +{ + app.DebugPrintf("Deleting schematic file\n"); + if(m_data.data != NULL) delete [] m_data.data; +} + +void ConsoleSchematicFile::save(DataOutputStream *dos) +{ + if(dos != NULL) + { + dos->writeInt(XBOX_SCHEMATIC_CURRENT_VERSION); + + dos->writeByte(APPROPRIATE_COMPRESSION_TYPE); + + dos->writeInt(m_xSize); + dos->writeInt(m_ySize); + dos->writeInt(m_zSize); + + byteArray ba(new BYTE[ m_data.length ], m_data.length); + Compression::getCompression()->CompressLZXRLE( ba.data, &ba.length, + m_data.data, m_data.length); + + dos->writeInt(ba.length); + dos->write(ba); + + save_tags(dos); + + delete [] ba.data; + } +} + +void ConsoleSchematicFile::load(DataInputStream *dis) +{ + if(dis != NULL) + { + // VERSION CHECK // + int version = dis->readInt(); + + Compression::ECompressionTypes compressionType = Compression::eCompressionType_LZXRLE; + + if (version > XBOX_SCHEMATIC_ORIGINAL_VERSION) // Or later versions + { + compressionType = (Compression::ECompressionTypes)dis->readByte(); + } + + if (version > XBOX_SCHEMATIC_CURRENT_VERSION) + assert(false && "Unrecognised schematic version!!"); + + m_xSize = dis->readInt(); + m_ySize = dis->readInt(); + m_zSize = dis->readInt(); + + int compressedSize = dis->readInt(); + byteArray compressedBuffer(compressedSize); + dis->readFully(compressedBuffer); + + if(m_data.data != NULL) + { + delete [] m_data.data; + m_data.data = NULL; + } + + if(compressionType == Compression::eCompressionType_None) + { + m_data = compressedBuffer; + } + else + { + unsigned int outputSize = m_xSize * m_ySize * m_zSize * 3/2; + m_data = byteArray(outputSize); + + switch(compressionType) + { + case Compression::eCompressionType_RLE: + Compression::getCompression()->DecompressRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); + break; + case APPROPRIATE_COMPRESSION_TYPE: + Compression::getCompression()->DecompressLZXRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); + break; + default: + app.DebugPrintf("Unrecognized compression type for Schematic file (%d)\n", (int)compressionType); + Compression::getCompression()->SetDecompressionType( (Compression::ECompressionTypes)compressionType ); + Compression::getCompression()->DecompressLZXRLE( m_data.data, &m_data.length, compressedBuffer.data, compressedSize); + Compression::getCompression()->SetDecompressionType( APPROPRIATE_COMPRESSION_TYPE ); + }; + + delete [] compressedBuffer.data; + } + + // READ TAGS // + CompoundTag *tag = NbtIo::read(dis); + ListTag *tileEntityTags = (ListTag *) tag->getList(L"TileEntities"); + if (tileEntityTags != NULL) + { + for (int i = 0; i < tileEntityTags->size(); i++) + { + CompoundTag *teTag = tileEntityTags->get(i); + shared_ptr te = TileEntity::loadStatic(teTag); + + if(te == NULL) + { +#ifndef _CONTENT_PACKAGE + app.DebugPrintf("ConsoleSchematicFile has read a NULL tile entity\n"); + __debugbreak(); +#endif + } + else + { + m_tileEntities.push_back(te); + } + } + } + ListTag *entityTags = (ListTag *) tag->getList(L"Entities"); + if (entityTags != NULL) + { + for (int i = 0; i < entityTags->size(); i++) + { + CompoundTag *eTag = entityTags->get(i); + eINSTANCEOF type = EntityIO::getType(eTag->getString(L"id")); + ListTag *pos = (ListTag *) eTag->getList(L"Pos"); + + double x = pos->get(0)->data; + double y = pos->get(1)->data; + double z = pos->get(2)->data; + + if( type == eTYPE_PAINTING || type == eTYPE_ITEM_FRAME ) + { + x = ((IntTag *) eTag->get(L"TileX") )->data; + y = ((IntTag *) eTag->get(L"TileY") )->data; + z = ((IntTag *) eTag->get(L"TileZ") )->data; + } +#ifdef _DEBUG + //app.DebugPrintf(1,"Loaded entity type %d at (%f,%f,%f)\n",(int)type,x,y,z); +#endif + m_entities.push_back( pair(Vec3::newPermanent(x,y,z),(CompoundTag *)eTag->copy())); + } + } + delete tag; + } +} + +void ConsoleSchematicFile::save_tags(DataOutputStream *dos) +{ + CompoundTag *tag = new CompoundTag(); + + ListTag *tileEntityTags = new ListTag(); + tag->put(L"TileEntities", tileEntityTags); + + for (AUTO_VAR(it, m_tileEntities.begin()); it != m_tileEntities.end(); it++) + { + CompoundTag *cTag = new CompoundTag(); + (*it)->save(cTag); + tileEntityTags->add(cTag); + } + + ListTag *entityTags = new ListTag(); + tag->put(L"Entities", entityTags); + + for (AUTO_VAR(it, m_entities.begin()); it != m_entities.end(); it++) + entityTags->add( (CompoundTag *)(*it).second->copy() ); + + NbtIo::write(tag,dos); + delete tag; +} + +__int64 ConsoleSchematicFile::applyBlocksAndData(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot) +{ + int xStart = max(destinationBox->x0, (double)chunk->x*16); + int xEnd = min(destinationBox->x1, (double)((xStart>>4)<<4) + 16); + + int yStart = destinationBox->y0; + int yEnd = destinationBox->y1; + if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight; + + int zStart = max(destinationBox->z0, (double)chunk->z*16); + int zEnd = min(destinationBox->z1, (double)((zStart>>4)<<4) + 16); + +#ifdef _DEBUG + app.DebugPrintf("Range is (%d,%d,%d) to (%d,%d,%d)\n",xStart,yStart,zStart,xEnd-1,yEnd-1,zEnd-1); +#endif + + int rowBlocksIncluded = (yEnd-yStart)*(zEnd-zStart); + int blocksIncluded = (xEnd-xStart)*rowBlocksIncluded; + + int rowBlockCount = getYSize() * getZSize(); + int totalBlockCount = getXSize() * rowBlockCount; + + byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); + PIXBeginNamedEvent(0,"Getting block data"); + chunk->getBlockData(blockData); + PIXEndNamedEvent(); + byteArray dataData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + PIXBeginNamedEvent(0,"Getting Data data"); + chunk->getDataData(dataData); + PIXEndNamedEvent(); + + // Ignore light data + int blockLightP = -1; + int skyLightP = -1; + if( rot == eSchematicRot_90 || rot == eSchematicRot_180 || rot == eSchematicRot_270 ) + { + int schematicXRow = 0; + int schematicZRow = 0; + int blocksP = 0; + int dataP = 0; + + for(int x = xStart; x < xEnd; ++x) + { + int x0 = x - chunk->x*16; + int x1 = x0 + 1; + + for(int z = zStart; z < zEnd; ++z) + { + int z0 = z - chunk->z*16; + int z1 = z0 + 1; + + chunkCoordToSchematicCoord(destinationBox, x, z, rot, schematicXRow, schematicZRow); + blocksP = (schematicXRow*rowBlockCount) + (schematicZRow*getYSize()); + dataP = totalBlockCount + (blocksP)/2; + + ConsoleSchematicFile::setBlocksAndData(chunk,blockData,dataData,m_data, x0, yStart, z0, x1, yEnd, z1, blocksP, dataP, blockLightP, skyLightP); + } + } + } + else if( rot == eSchematicRot_0 ) + { + // The initial pointer offsets for the different data types + int schematicXRow = xStart - destinationBox->x0; + int schematicZRow = zStart - destinationBox->z0; + int blocksP = (schematicXRow*rowBlockCount) + (schematicZRow*getYSize()); + int dataP = totalBlockCount + (schematicXRow*rowBlockCount + (schematicZRow*getYSize()))/2; + + for(int x = xStart; x < xEnd; ++x) + { + int x0 = x - chunk->x*16; + int x1 = x0 + 1; + + int z0 = zStart - chunk->z*16; + int z1 = zEnd - chunk->z*16; + + ConsoleSchematicFile::setBlocksAndData(chunk,blockData,dataData,m_data, x0, yStart, z0, x1, yEnd, z1, blocksP, dataP, blockLightP, skyLightP); + // update all pointer positions + // For z start to z end + // Set blocks and data + // increment z by the right amount + blocksP += (rowBlockCount-rowBlocksIncluded); + dataP += (rowBlockCount-rowBlocksIncluded)/2; + } + } + else + { + app.DebugPrintf("ERROR: Rotation of block and data not implemented!!\n"); + } + + // 4J Stu - Hack for ME pack to replace sand with end stone in schematics + //for(int i = 0; i < blockData.length; ++i) + //{ + // if(blockData[i] == Tile::sand_Id || blockData[i] == Tile::sandStone_Id) + // { + // blockData[i] = Tile::whiteStone_Id; + // } + //} + + PIXBeginNamedEvent(0,"Setting Block data"); + chunk->setBlockData(blockData); + PIXEndNamedEvent(); + delete blockData.data; + chunk->recalcHeightmapOnly(); + PIXBeginNamedEvent(0,"Setting Data data"); + chunk->setDataData(dataData); + PIXEndNamedEvent(); + delete dataData.data; + + // A basic pass through to roughly do the lighting. At this point of post-processing, we don't have all the neighbouring chunks loaded in, + // so any lighting here should be things that won't propagate out of this chunk. + for( int xx = xStart ; xx < xEnd; xx++ ) + for( int y = yStart ; y < yEnd; y++ ) + for( int zz = zStart ; zz < zEnd; zz++ ) + { + int x = xx - chunk->x * 16; + int z = zz - chunk->z * 16; + chunk->setBrightness(LightLayer::Block,x,y,z,0); + if( chunk->getTile(x,y,z) ) + { + chunk->setBrightness(LightLayer::Sky,x,y,z,0); + } + else + { + if( chunk->isSkyLit(x,y,z) ) + { + chunk->setBrightness(LightLayer::Sky,x,y,z,15); + } + else + { + chunk->setBrightness(LightLayer::Sky,x,y,z,0); + } + } + } + + return blocksIncluded; +} + +// At the point that this is called, we have all the neighbouring chunks loaded in (and generally post-processed, apart from this lighting pass), so +// we can do the sort of lighting that might propagate out of the chunk. +__int64 ConsoleSchematicFile::applyLighting(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot) +{ + int xStart = max(destinationBox->x0, (double)chunk->x*16); + int xEnd = min(destinationBox->x1, (double)((xStart>>4)<<4) + 16); + + int yStart = destinationBox->y0; + int yEnd = destinationBox->y1; + if(yEnd > Level::maxBuildHeight) yEnd = Level::maxBuildHeight; + + int zStart = max(destinationBox->z0, (double)chunk->z*16); + int zEnd = min(destinationBox->z1, (double)((zStart>>4)<<4) + 16); + + int rowBlocksIncluded = (yEnd-yStart)*(zEnd-zStart); + int blocksIncluded = (xEnd-xStart)*rowBlocksIncluded; + + // Now actually do a checkLight on blocks that might need it, which should more accurately put everything in place + for( int xx = xStart ; xx < xEnd; xx++ ) + for( int y = yStart ; y < yEnd; y++ ) + for( int zz = zStart ; zz < zEnd; zz++ ) + { + int x = xx - chunk->x * 16; + int z = zz - chunk->z * 16; + + if( y <= chunk->getHeightmap( x, z ) ) + { + chunk->level->checkLight(LightLayer::Sky, xx, y, zz, true); + } + if( Tile::lightEmission[chunk->getTile(x,y,z)] ) + { + // Note that this lighting passes a rootOnlyEmissive flag of true, which means that only the location xx/y/zz is considered + // as possibly being a source of emissive light, not other tiles that we might encounter whilst propagating the light from + // the start location. If we don't do this, and Do encounter another emissive source in the radius of influence that the first + // light source had, then we'll start also lighting from that tile but won't actually be able to progatate that second light + // fully since checkLight only has a finite radius of 17 from the start position that it can light. Then when we do a checkLight + // on the second light later, it won't bother doing anything because the light level at the location of the tile itself will be correct. + chunk->level->checkLight(LightLayer::Block, xx, y, zz, true, true); + } + } + + return blocksIncluded; +} + +void ConsoleSchematicFile::chunkCoordToSchematicCoord(AABB *destinationBox, int chunkX, int chunkZ, ESchematicRotation rot, int &schematicX, int &schematicZ) +{ + switch(rot) + { + case eSchematicRot_90: + // schematicX decreases as chunkZ increases + // schematicZ increases as chunkX increases + schematicX = chunkZ - destinationBox->z0; + schematicZ = (destinationBox->x1 - 1 - destinationBox->x0) - (chunkX - destinationBox->x0); + break; + case eSchematicRot_180: + // schematicX decreases as chunkX increases + // schematicZ decreases as chunkZ increases + schematicX = (destinationBox->x1 - 1 - destinationBox->x0) - (chunkX - destinationBox->x0); + schematicZ = (destinationBox->z1 - 1 - destinationBox->z0) - (chunkZ - destinationBox->z0); + break; + case eSchematicRot_270: + // schematicX increases as chunkZ increases + // shcematicZ decreases as chunkX increases + schematicX = (destinationBox->z1 - 1 - destinationBox->z0) - (chunkZ - destinationBox->z0); + schematicZ = chunkX - destinationBox->x0; + break; + case eSchematicRot_0: + default: + // schematicX increases as chunkX increases + // schematicZ increases as chunkZ increases + schematicX = chunkX - destinationBox->x0; + schematicZ = chunkZ - destinationBox->z0; + break; + }; +} + +void ConsoleSchematicFile::schematicCoordToChunkCoord(AABB *destinationBox, double schematicX, double schematicZ, ESchematicRotation rot, double &chunkX, double &chunkZ) +{ + switch(rot) + { + case eSchematicRot_90: + // schematicX decreases as chunkZ increases + // schematicZ increases as chunkX increases + chunkX = (destinationBox->x1 - 1 - schematicZ); + chunkZ = schematicX + destinationBox->z0; + break; + case eSchematicRot_180: + // schematicX decreases as chunkX increases + // schematicZ decreases as chunkZ increases + chunkX = (destinationBox->x1 - 1 - schematicX); + chunkZ = (destinationBox->z1 - 1 - schematicZ); + break; + case eSchematicRot_270: + // schematicX increases as chunkZ increases + // shcematicZ decreases as chunkX increases + chunkX = schematicZ + destinationBox->x0; + chunkZ = (destinationBox->z1 - 1 - schematicX); + break; + case eSchematicRot_0: + default: + // schematicX increases as chunkX increases + // schematicZ increases as chunkZ increases + chunkX = schematicX + destinationBox->x0; + chunkZ = schematicZ + destinationBox->z0; + break; + }; +} + +void ConsoleSchematicFile::applyTileEntities(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot) +{ + for(AUTO_VAR(it, m_tileEntities.begin()); it != m_tileEntities.end();++it) + { + shared_ptr te = *it; + + double targetX = te->x; + double targetY = te->y + destinationBox->y0; + double targetZ = te->z; + + schematicCoordToChunkCoord(destinationBox, te->x, te->z, rot, targetX, targetZ); + + Vec3 *pos = Vec3::newTemp(targetX,targetY,targetZ); + if( chunkBox->containsIncludingLowerBound(pos) ) + { + shared_ptr teCopy = chunk->getTileEntity( (int)targetX & 15, (int)targetY & 15, (int)targetZ & 15 ); + + if ( teCopy != NULL ) + { + CompoundTag *teData = new CompoundTag(); + te->save(teData); + + teCopy->load(teData); + + delete teData; + + // Adjust the tileEntity position to world coords from schematic co-ords + teCopy->x = targetX; + teCopy->y = targetY; + teCopy->z = targetZ; + + // Remove the current tile entity + //chunk->removeTileEntity( (int)targetX & 15, (int)targetY & 15, (int)targetZ & 15 ); + } + else + { + teCopy = te->clone(); + + // Adjust the tileEntity position to world coords from schematic co-ords + teCopy->x = targetX; + teCopy->y = targetY; + teCopy->z = targetZ; + chunk->addTileEntity(teCopy); + } + + teCopy->setChanged(); + } + } + for(AUTO_VAR(it, m_entities.begin()); it != m_entities.end();) + { + Vec3 *source = it->first; + + double targetX = source->x; + double targetY = source->y + destinationBox->y0; + double targetZ = source->z; + schematicCoordToChunkCoord(destinationBox, source->x, source->z, rot, targetX, targetZ); + + // Add 0.01 as the AABB::contains function returns false if a value is <= the lower bound + Vec3 *pos = Vec3::newTemp(targetX+0.01,targetY+0.01,targetZ+0.01); + if( !chunkBox->containsIncludingLowerBound(pos) ) + { + ++it; + continue; + } + + CompoundTag *eTag = it->second; + shared_ptr e = EntityIO::loadStatic(eTag, NULL); + + if( e->GetType() == eTYPE_PAINTING ) + { + shared_ptr painting = dynamic_pointer_cast(e); + + double tileX = painting->xTile; + double tileZ = painting->zTile; + schematicCoordToChunkCoord(destinationBox, painting->xTile, painting->zTile, rot, tileX, tileZ); + + painting->yTile += destinationBox->y0; + painting->xTile = tileX; + painting->zTile = tileZ; + painting->setDir(painting->dir); + } + else if( e->GetType() == eTYPE_ITEM_FRAME ) + { + shared_ptr frame = dynamic_pointer_cast(e); + + double tileX = frame->xTile; + double tileZ = frame->zTile; + schematicCoordToChunkCoord(destinationBox, frame->xTile, frame->zTile, rot, tileX, tileZ); + + frame->yTile += destinationBox->y0; + frame->xTile = tileX; + frame->zTile = tileZ; + frame->setDir(frame->dir); + } + else + { + e->absMoveTo(targetX, targetY, targetZ,e->yRot,e->xRot); + } +#ifdef _DEBUG + app.DebugPrintf("Adding entity type %d at (%f,%f,%f)\n",e->GetType(),e->x,e->y,e->z); +#endif + e->setLevel(chunk->level); + e->resetSmallId(); + e->setDespawnProtected(); // default to being protected against despawning + chunk->level->addEntity(e); + + // 4J Stu - Until we can copy every type of entity, remove them from this vector + // This means that the entities will only exist in the first use of the schematic that is processed + //it = m_entities.erase(it); + ++it; + } +} + +void ConsoleSchematicFile::generateSchematicFile(DataOutputStream *dos, Level *level, int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, bool bSaveMobs, Compression::ECompressionTypes compressionType) +{ + assert(xEnd > xStart); + assert(yEnd > yStart); + assert(zEnd > zStart); + // 4J Stu - Enforce even numbered positions to start with to avoid problems with half-bytes in data + + // We want the start to be even + if(xStart > 0 && xStart%2 != 0) + xStart-=1; + else if(xStart < 0 && xStart%2 !=0) + xStart-=1; + if(yStart < 0) yStart = 0; + else if(yStart > 0 && yStart%2 != 0) + yStart-=1; + if(zStart > 0 && zStart%2 != 0) + zStart-=1; + else if(zStart < 0 && zStart%2 !=0) + zStart-=1; + + // We want the end to be odd to have a total size that is even + if(xEnd > 0 && xEnd%2 == 0) + xEnd+=1; + else if(xEnd < 0 && xEnd%2 ==0) + xEnd+=1; + if(yEnd > Level::maxBuildHeight) + yEnd = Level::maxBuildHeight; + else if(yEnd > 0 && yEnd%2 == 0) + yEnd+=1; + else if(yEnd < 0 && yEnd%2 ==0) + yEnd+=1; + if(zEnd > 0 && zEnd%2 == 0) + zEnd+=1; + else if(zEnd < 0 && zEnd%2 ==0) + zEnd+=1; + + int xSize = xEnd - xStart + 1; + int ySize = yEnd - yStart + 1; + int zSize = zEnd - zStart + 1; + + app.DebugPrintf("Generating schematic file for area (%d,%d,%d) to (%d,%d,%d), %dx%dx%d\n",xStart,yStart,zStart,xEnd,yEnd,zEnd,xSize,ySize,zSize); + + if(dos != NULL) dos->writeInt(XBOX_SCHEMATIC_CURRENT_VERSION); + + if(dos != NULL) dos->writeByte(compressionType); + + //Write xSize + if(dos != NULL) dos->writeInt(xSize); + + //Write ySize + if(dos != NULL) dos->writeInt(ySize); + + //Write zSize + if(dos != NULL) dos->writeInt(zSize); + + //byteArray rawBuffer = level->getBlocksAndData(xStart, yStart, zStart, xSize, ySize, zSize, false); + int xRowSize = ySize * zSize; + int blockCount = xSize * xRowSize; + byteArray result( blockCount * 3 / 2 ); + + // Position pointers into the data when not ordered by chunk + int p = 0; + int dataP = blockCount; + int blockLightP = -1; + int skyLightP = -1; + + int y0 = yStart; + int y1 = yStart + ySize; + if (y0 < 0) y0 = 0; + if (y1 > Level::maxBuildHeight) y1 = Level::maxBuildHeight; + + // Every x is a whole row + for(int xPos = xStart; xPos < xStart + xSize; ++xPos) + { + int xc = xPos >> 4; + + int x0 = xPos - xc * 16; + if (x0 < 0) x0 = 0; + int x1 = x0 + 1; + if (x1 > 16) x1 = 16; + + for(int zPos = zStart; zPos < zStart + zSize;) + { + int zc = zPos >> 4; + + int z0 = zStart - zc * 16; + int z1 = zStart + zSize - zc * 16; + if (z0 < 0) z0 = 0; + if (z1 > 16) z1 = 16; + getBlocksAndData(level->getChunk(xc, zc), &result, x0, y0, z0, x1, y1, z1, p, dataP, blockLightP, skyLightP); + zPos += (z1-z0); + } + } + +#ifndef _CONTENT_PACKAGE + if(p!=blockCount) __debugbreak(); +#endif + + // We don't know how this will compress - just make a fixed length buffer to initially decompress into + // Some small sets of blocks can end up compressing into something bigger than their source + unsigned int inputSize = blockCount * 3 / 2; + unsigned char *ucTemp = new unsigned char[inputSize]; + + switch(compressionType) + { + case Compression::eCompressionType_LZXRLE: + Compression::getCompression()->CompressLZXRLE( ucTemp, &inputSize, result.data, (unsigned int) result.length ); + break; + case Compression::eCompressionType_RLE: + Compression::getCompression()->CompressRLE( ucTemp, &inputSize, result.data, (unsigned int) result.length ); + break; + case Compression::eCompressionType_None: + default: + memcpy( ucTemp, result.data, inputSize ); + break; + }; + + delete [] result.data; + byteArray buffer = byteArray(ucTemp,inputSize); + + if(dos != NULL) dos->writeInt(inputSize); + if(dos != NULL) dos->write(buffer); + delete [] buffer.data; + + CompoundTag tag; + ListTag *tileEntitiesTag = new ListTag(L"tileEntities"); + + int xc0 = xStart >> 4; + int zc0 = zStart >> 4; + int xc1 = (xStart + xSize - 1) >> 4; + int zc1 = (zStart + zSize - 1) >> 4; + + for (int xc = xc0; xc <= xc1; xc++) + { + for (int zc = zc0; zc <= zc1; zc++) + { + vector > *tileEntities = getTileEntitiesInRegion(level->getChunk(xc, zc), xStart, yStart, zStart, xStart + xSize, yStart + ySize, zStart + zSize); + for(AUTO_VAR(it, tileEntities->begin()); it != tileEntities->end(); ++it) + { + shared_ptr te = *it; + CompoundTag *teTag = new CompoundTag(); + shared_ptr teCopy = te->clone(); + + // Adjust the tileEntity position to schematic coords from world co-ords + teCopy->x -= xStart; + teCopy->y -= yStart; + teCopy->z -= zStart; + teCopy->save(teTag); + tileEntitiesTag->add(teTag); + } + delete tileEntities; + } + } + tag.put(L"TileEntities", tileEntitiesTag); + + AABB *bb = AABB::newTemp(xStart,yStart,zStart,xEnd,yEnd,zEnd); + vector > *entities = level->getEntities(nullptr, bb); + ListTag *entitiesTag = new ListTag(L"entities"); + + for(AUTO_VAR(it, entities->begin()); it != entities->end(); ++it) + { + shared_ptr e = *it; + + bool mobCanBeSaved = false; + if(bSaveMobs) + { + if( ( e->GetType() & eTYPE_MONSTER ) || ( e->GetType() & eTYPE_WATERANIMAL ) || ( e->GetType() & eTYPE_ANIMAL ) || + ( e->GetType() == eTYPE_CHICKEN ) || ( e->GetType() == eTYPE_WOLF ) || ( e->GetType() == eTYPE_VILLAGER) || ( e->GetType() == eTYPE_MUSHROOMCOW ) ) + { + mobCanBeSaved = true; + } + } + if(mobCanBeSaved || e->GetType() == eTYPE_MINECART || e->GetType() == eTYPE_BOAT || e->GetType() == eTYPE_PAINTING || e->GetType() == eTYPE_ITEM_FRAME) + { + CompoundTag *eTag = new CompoundTag(); + if( e->save(eTag) ) + { + ListTag *pos = (ListTag *) eTag->getList(L"Pos"); + + pos->get(0)->data -= xStart; + pos->get(1)->data -= yStart; + pos->get(2)->data -= zStart; + + if( e->GetType() == eTYPE_PAINTING || e->GetType() == eTYPE_ITEM_FRAME ) + { + ((IntTag *) eTag->get(L"TileX") )->data -= xStart; + ((IntTag *) eTag->get(L"TileY") )->data -= yStart; + ((IntTag *) eTag->get(L"TileZ") )->data -= zStart; + } + + entitiesTag->add(eTag); + } + } + } + + tag.put(L"Entities", entitiesTag); + + if(dos != NULL) NbtIo::write(&tag,dos); +} + +void ConsoleSchematicFile::getBlocksAndData(LevelChunk *chunk, byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP) +{ + // 4J Stu - Needs updated to work with higher worlds, should still work with non-optimised version below + //int xs = x1 - x0; + //int ys = y1 - y0; + //int zs = z1 - z0; + //if (xs * ys * zs == LevelChunk::BLOCKS_LENGTH) + //{ + // byteArray blockData = byteArray(data->data + blocksP, Level::CHUNK_TILE_COUNT); + // chunk->getBlockData(blockData); + // blocksP += blockData.length; + + // byteArray dataData = byteArray(data->data + dataP, 16384); + // chunk->getBlockLightData(dataData); + // dataP += dataData.length; + + // byteArray blockLightData = byteArray(data->data + blockLightP, 16384); + // chunk->getBlockLightData(blockLightData); + // blockLightP += blockLightData.length; + + // byteArray skyLightData = byteArray(data->data + skyLightP, 16384); + // chunk->getSkyLightData(skyLightData); + // skyLightP += skyLightData.length; + // return; + //} + + bool bHasLower, bHasUpper; + bHasLower = bHasUpper = false; + int lowerY0, lowerY1, upperY0, upperY1; + lowerY0 = upperY0 = y0; + lowerY1 = upperY1 = y1; + + int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + lowerY0 = y0; + lowerY1 = min(y1, compressedHeight); + bHasLower = true; + } + if(y1 >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + upperY0 = max(y0, compressedHeight) - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + upperY1 = y1 - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + bHasUpper = true; + } + + byteArray blockData = byteArray(Level::CHUNK_TILE_COUNT); + chunk->getBlockData(blockData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0; + int len = lowerY1 - lowerY0; + System::arraycopy(blockData, slot, data, blocksP, len); + blocksP += len; + } + if(bHasUpper) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES; + int len = upperY1 - upperY0; + System::arraycopy(blockData, slot, data, blocksP, len); + blocksP += len; + } + } + delete blockData.data; + + byteArray dataData = byteArray(Level::CHUNK_TILE_COUNT); + chunk->getDataData(dataData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(dataData, slot, data, dataP, len); + dataP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES) >> 1; + int len = (upperY1 - upperY0) / 2; + System::arraycopy(dataData, slot, data, dataP, len); + dataP += len; + } + } + delete dataData.data; + + // 4J Stu - Allow ignoring light data + if(blockLightP > -1) + { + byteArray blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getBlockLightData(blockLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(blockLightData, slot, data, blockLightP, len); + blockLightP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(blockLightData, slot, data, blockLightP, len); + blockLightP += len; + } + } + delete blockLightData.data; + } + + + // 4J Stu - Allow ignoring light data + if(skyLightP > -1) + { + byteArray skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getSkyLightData(skyLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(skyLightData, slot, data, skyLightP, len); + skyLightP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(skyLightData, slot, data, skyLightP, len); + skyLightP += len; + } + } + delete skyLightData.data; + } + + return; +} + +void ConsoleSchematicFile::setBlocksAndData(LevelChunk *chunk, byteArray blockData, byteArray dataData, byteArray inputData, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP) +{ + bool bHasLower, bHasUpper; + bHasLower = bHasUpper = false; + int lowerY0, lowerY1, upperY0, upperY1; + lowerY0 = upperY0 = y0; + lowerY1 = upperY1 = y1; + + int compressedHeight = Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + if(y0 < Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + lowerY0 = y0; + lowerY1 = min(y1, compressedHeight); + bHasLower = true; + } + if(y1 >= Level::COMPRESSED_CHUNK_SECTION_HEIGHT) + { + upperY0 = max(y0, compressedHeight) - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + upperY1 = y1 - Level::COMPRESSED_CHUNK_SECTION_HEIGHT; + bHasUpper = true; + } + PIXBeginNamedEvent(0,"Applying block data"); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0; + int len = lowerY1 - lowerY0; + System::arraycopy(inputData, blocksP, &blockData, slot, len); + blocksP += len; + } + if(bHasUpper) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES; + int len = upperY1 - upperY0; + System::arraycopy(inputData, blocksP, &blockData, slot, len); + blocksP += len; + } + } + PIXEndNamedEvent(); + + PIXBeginNamedEvent(0,"Applying Data data"); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(inputData, dataP, &dataData, slot, len); + dataP += len; + } + if(bHasUpper) + { + int slot = ((x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + Level::COMPRESSED_CHUNK_SECTION_TILES) >> 1; + int len = (upperY1 - upperY0) / 2; + System::arraycopy(inputData, dataP, &dataData, slot, len); + dataP += len; + } + } + PIXEndNamedEvent(); + // 4J Stu - Allow ignoring light data + if(blockLightP > -1) + { + byteArray blockLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getBlockLightData(blockLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(inputData, blockLightP, &blockLightData, slot, len); + blockLightP += len; + } + if(bHasUpper) + { + int slot = ( (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) >> 1) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(inputData, blockLightP, &blockLightData, slot, len); + blockLightP += len; + } + } + chunk->setBlockLightData(blockLightData); + delete blockLightData.data; + } + + // 4J Stu - Allow ignoring light data + if(skyLightP > -1) + { + byteArray skyLightData = byteArray(Level::HALF_CHUNK_TILE_COUNT); + chunk->getSkyLightData(skyLightData); + for (int x = x0; x < x1; x++) + for (int z = z0; z < z1; z++) + { + if(bHasLower) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | lowerY0) >> 1; + int len = (lowerY1 - lowerY0) / 2; + System::arraycopy(inputData, skyLightP, &skyLightData, slot, len); + skyLightP += len; + } + if(bHasUpper) + { + int slot = (x << Level::genDepthBitsPlusFour | z << Level::genDepthBits | upperY0) + (Level::COMPRESSED_CHUNK_SECTION_TILES/2); + int len = (upperY1 - upperY0) / 2; + System::arraycopy(inputData, skyLightP, &skyLightData, slot, len); + skyLightP += len; + } + } + chunk->setSkyLightData(skyLightData); + delete skyLightData.data; + } +} + +vector > *ConsoleSchematicFile::getTileEntitiesInRegion(LevelChunk *chunk, int x0, int y0, int z0, int x1, int y1, int z1) +{ + vector > *result = new vector >; + for (AUTO_VAR(it, chunk->tileEntities.begin()); it != chunk->tileEntities.end(); ++it) + { + shared_ptr te = it->second; + if (te->x >= x0 && te->y >= y0 && te->z >= z0 && te->x < x1 && te->y < y1 && te->z < z1) + { + result->push_back(te); + } + } + return result; +} diff --git a/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h new file mode 100644 index 0000000..f37a605 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/ConsoleSchematicFile.h @@ -0,0 +1,90 @@ +#pragma once +using namespace std; + +#define XBOX_SCHEMATIC_ORIGINAL_VERSION 1 +#define XBOX_SCHEMATIC_CURRENT_VERSION 2 + +#include "..\..\..\Minecraft.World\ArrayWithLength.h" + +class Level; +class DataOutputStream; +class DataInputStream; +class TileEntity; +class LevelChunk; +class AABB; +class Vec3; + +class ConsoleSchematicFile +{ +public: + enum ESchematicRotation + { + eSchematicRot_0, + eSchematicRot_90, + eSchematicRot_180, + eSchematicRot_270 + }; +private: + int m_refCount; + +public: + void incrementRefCount() { ++m_refCount; } + void decrementRefCount() { --m_refCount; } + bool shouldDelete() { return m_refCount <= 0; } + + typedef struct _XboxSchematicInitParam + { + wchar_t name[64]; + int startX; + int startY; + int startZ; + int endX; + int endY; + int endZ; + bool bSaveMobs; + + Compression::ECompressionTypes compressionType; + + _XboxSchematicInitParam() + { + ZeroMemory(name,64*(sizeof(wchar_t))); + startX = startY = startZ = endX = endY = endZ = 0; + bSaveMobs = false; + compressionType = Compression::eCompressionType_None; + } + } XboxSchematicInitParam; +private: + int m_xSize, m_ySize, m_zSize; + vector > m_tileEntities; + vector< pair > m_entities; + +public: + byteArray m_data; + +public: + ConsoleSchematicFile(); + ~ConsoleSchematicFile(); + + int getXSize() { return m_xSize; } + int getYSize() { return m_ySize; } + int getZSize() { return m_zSize; } + + void save(DataOutputStream *dos); + void load(DataInputStream *dis); + + __int64 applyBlocksAndData(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot); + __int64 applyLighting(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot); + void applyTileEntities(LevelChunk *chunk, AABB *chunkBox, AABB *destinationBox, ESchematicRotation rot); + + static void generateSchematicFile(DataOutputStream *dos, Level *level, int xStart, int yStart, int zStart, int xEnd, int yEnd, int zEnd, bool bSaveMobs, Compression::ECompressionTypes); + static void setBlocksAndData(LevelChunk *chunk, byteArray blockData, byteArray dataData, byteArray data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP); +private: + void save_tags(DataOutputStream *dos); + void load_tags(DataInputStream *dis); + + static void getBlocksAndData(LevelChunk *chunk, byteArray *data, int x0, int y0, int z0, int x1, int y1, int z1, int &blocksP, int &dataP, int &blockLightP, int &skyLightP); + static vector > *getTileEntitiesInRegion(LevelChunk *chunk, int x0, int y0, int z0, int x1, int y1, int z1); + + void chunkCoordToSchematicCoord(AABB *destinationBox, int chunkX, int chunkZ, ESchematicRotation rot, int &schematicX, int &schematicZ); + void schematicCoordToChunkCoord(AABB *destinationBox, double schematicX, double schematicZ, ESchematicRotation rot, double &chunkX, double &chunkZ); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRule.cpp b/Minecraft.Client/Common/GameRules/GameRule.cpp new file mode 100644 index 0000000..34d6196 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRule.cpp @@ -0,0 +1,97 @@ +#include "stdafx.h" +#include "ConsoleGameRules.h" + +GameRule::GameRule(GameRuleDefinition *definition, Connection *connection) +{ + m_definition = definition; + m_connection = connection; +} + +GameRule::~GameRule() +{ + for(AUTO_VAR(it, m_parameters.begin()); it != m_parameters.end(); ++it) + { + if(it->second.isPointer) + { + delete it->second.gr; + } + } +} + +GameRule::ValueType GameRule::getParameter(const wstring ¶meterName) +{ + if(m_parameters.find(parameterName) == m_parameters.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"WARNING: Parameter %ls was not set before being fetched\n", parameterName.c_str()); + __debugbreak(); +#endif + } + return m_parameters[parameterName]; +} + +void GameRule::setParameter(const wstring ¶meterName,ValueType value) +{ + if(m_parameters.find(parameterName) == m_parameters.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Adding parameter %ls to GameRule\n", parameterName.c_str()); +#endif + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"Setting parameter %ls for GameRule\n", parameterName.c_str()); +#endif + } + m_parameters[parameterName] = value; +} + +GameRuleDefinition *GameRule::getGameRuleDefinition() +{ + return m_definition; +} + +void GameRule::onUseTile(int tileId, int x, int y, int z) { m_definition->onUseTile(this,tileId,x,y,z); } +void GameRule::onCollectItem(shared_ptr item) { m_definition->onCollectItem(this,item); } + +void GameRule::write(DataOutputStream *dos) +{ + // Find required parameters. + dos->writeInt(m_parameters.size()); + for (AUTO_VAR(it, m_parameters.begin()); it != m_parameters.end(); it++) + { + wstring pName = (*it).first; + ValueType vType = (*it).second; + + dos->writeUTF( (*it).first ); + dos->writeBoolean( vType.isPointer ); + + if (vType.isPointer) + vType.gr->write(dos); + else + dos->writeLong( vType.i64 ); + } +} + +void GameRule::read(DataInputStream *dis) +{ + int savedParams = dis->readInt(); + for (int i = 0; i < savedParams; i++) + { + wstring pNames = dis->readUTF(); + + ValueType vType = getParameter(pNames); + + if (dis->readBoolean()) + { + vType.gr->read(dis); + } + else + { + vType.isPointer = false; + vType.i64 = dis->readLong(); + setParameter(pNames, vType); + } + } +} diff --git a/Minecraft.Client/Common/GameRules/GameRule.h b/Minecraft.Client/Common/GameRules/GameRule.h new file mode 100644 index 0000000..bdc2cef --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRule.h @@ -0,0 +1,62 @@ +#pragma once +using namespace std; + +#include + +class CompoundTag; +class GameRuleDefinition; +class Connection; + +// A game rule maintains the state for one particular definition +class GameRule +{ +public: + typedef struct _ValueType + { + union{ + __int64 i64; + int i; + char c; + bool b; + float f; + double d; + GameRule *gr; + }; + bool isPointer; + + _ValueType() + { + i64 = 0; + isPointer = false; + } + } ValueType; + +private: + GameRuleDefinition *m_definition; + Connection *m_connection; + +public: + typedef unordered_map stringValueMapType; + stringValueMapType m_parameters; // These are the members of this rule that maintain it's state + +public: + GameRule(GameRuleDefinition *definition, Connection *connection = NULL); + virtual ~GameRule(); + + Connection *getConnection() { return m_connection; } + + ValueType getParameter(const wstring ¶meterName); + void setParameter(const wstring ¶meterName,ValueType value); + GameRuleDefinition *getGameRuleDefinition(); + + // All the hooks go here + void onUseTile(int tileId, int x, int y, int z); + void onCollectItem(shared_ptr item); + + // 4J-JEV: For saving. + //CompoundTag *toTags(unordered_map *map); + //static GameRule *fromTags(Connection *c, CompoundTag *cTag, vector *grds); + + void write(DataOutputStream *dos); + void read(DataInputStream *dos); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp new file mode 100644 index 0000000..b63687c --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleDefinition.cpp @@ -0,0 +1,151 @@ +#include "stdafx.h" +#include "..\..\WstringLookup.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "ConsoleGameRules.h" + +GameRuleDefinition::GameRuleDefinition() +{ + m_descriptionId = L""; + m_promptId = L""; + m_4JDataValue = 0; +} + +void GameRuleDefinition::write(DataOutputStream *dos) +{ + // Write EGameRuleType. + ConsoleGameRules::EGameRuleType eType = getActionType(); + assert( eType != ConsoleGameRules::eGameRuleType_Invalid ); + ConsoleGameRules::write(dos, eType); // stringID + + writeAttributes(dos, 0); + + // 4J-JEV: Get children. + vector *children = new vector(); + getChildren( children ); + + // Write children. + dos->writeInt( children->size() ); + for (AUTO_VAR(it, children->begin()); it != children->end(); it++) + (*it)->write(dos); +} + +void GameRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + dos->writeInt(numAttributes + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_descriptionName); + dos->writeUTF(m_descriptionId); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_promptName); + dos->writeUTF(m_promptId); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_dataTag); + dos->writeUTF(_toString(m_4JDataValue)); +} + +void GameRuleDefinition::getChildren(vector *children) {} + +GameRuleDefinition *GameRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + return NULL; +} + +void GameRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"descriptionName") == 0) + { + m_descriptionId = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Adding parameter descriptionId=%ls\n",m_descriptionId.c_str()); +#endif + } + else if(attributeName.compare(L"promptName") == 0) + { + m_promptId = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Adding parameter m_promptId=%ls\n",m_promptId.c_str()); +#endif + } + else if(attributeName.compare(L"dataTag") == 0) + { + m_4JDataValue = _fromString(attributeValue); + app.DebugPrintf("GameRuleDefinition: Adding parameter m_4JDataValue=%d\n",m_4JDataValue); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"GameRuleDefinition: Attempted to add invalid attribute: %ls\n", attributeName.c_str()); +#endif + } +} + +void GameRuleDefinition::populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule) +{ + GameRule::ValueType value; + value.b = false; + rule->setParameter(L"bComplete",value); +} + +bool GameRuleDefinition::getComplete(GameRule *rule) +{ + GameRule::ValueType value; + value = rule->getParameter(L"bComplete"); + return value.b; +} + +void GameRuleDefinition::setComplete(GameRule *rule, bool val) +{ + GameRule::ValueType value; + value = rule->getParameter(L"bComplete"); + value.b = val; + rule->setParameter(L"bComplete",value); +} + +vector *GameRuleDefinition::enumerate() +{ + // Get Vector. + vector *gRules; + gRules = new vector(); + gRules->push_back(this); + getChildren(gRules); + return gRules; +} + +unordered_map *GameRuleDefinition::enumerateMap() +{ + unordered_map *out + = new unordered_map(); + + int i = 0; + vector *gRules = enumerate(); + for (AUTO_VAR(it, gRules->begin()); it != gRules->end(); it++) + out->insert( pair( *it, i++ ) ); + + return out; +} + +GameRulesInstance *GameRuleDefinition::generateNewGameRulesInstance(GameRulesInstance::EGameRulesInstanceType type, LevelRuleset *rules, Connection *connection) +{ + GameRulesInstance *manager = new GameRulesInstance(rules, connection); + + rules->populateGameRule(type, manager); + + return manager; +} + +wstring GameRuleDefinition::generateDescriptionString(ConsoleGameRules::EGameRuleType defType, const wstring &description, void *data, int dataLength) +{ + wstring formatted = description; + switch(defType) + { + case ConsoleGameRules::eGameRuleType_CompleteAllRule: + formatted = CompleteAllRuleDefinition::generateDescriptionString(description,data,dataLength); + break; + default: + break; + }; + return formatted; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRuleDefinition.h b/Minecraft.Client/Common/GameRules/GameRuleDefinition.h new file mode 100644 index 0000000..afec8fb --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleDefinition.h @@ -0,0 +1,66 @@ +#pragma once +using namespace std; +#include +#include + +#include "..\..\..\Minecraft.World\ItemInstance.h" +#include "ConsoleGameRulesConstants.h" + +#include "GameRulesInstance.h" + +class GameRule; +class LevelRuleset; +class Player; +class WstringLookup; + +class GameRuleDefinition +{ +private: + // Owner type defines who this rule applies to + GameRulesInstance::EGameRulesInstanceType m_ownerType; + +protected: + // These attributes should map to those in the XSD GameRuleType + wstring m_descriptionId; + wstring m_promptId; + int m_4JDataValue; + +public: + GameRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() = 0; + + void setOwnerType(GameRulesInstance::EGameRulesInstanceType ownerType) { m_ownerType = ownerType;} + + virtual void write(DataOutputStream *); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void getChildren(vector *); + + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual void populateGameRule(GameRulesInstance::EGameRulesInstanceType type, GameRule *rule); + + bool getComplete(GameRule *rule); + void setComplete(GameRule *rule, bool val); + + virtual int getGoal() { return 0; } + virtual int getProgress(GameRule *rule) { return 0; } + + virtual int getIcon() { return -1; } + virtual int getAuxValue() { return 0; } + + // Here we should have functions for all the hooks, with a GameRule* as the first parameter + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z) { return false; } + virtual bool onCollectItem(GameRule *rule, shared_ptr item) { return false; } + virtual void postProcessPlayer(shared_ptr player) { } + + vector *enumerate(); + unordered_map *enumerateMap(); + + // Static functions + static GameRulesInstance *generateNewGameRulesInstance(GameRulesInstance::EGameRulesInstanceType type, LevelRuleset *rules, Connection *connection); + static wstring generateDescriptionString(ConsoleGameRules::EGameRuleType defType, const wstring &description, void *data = NULL, int dataLength = 0); + +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/GameRuleManager.cpp b/Minecraft.Client/Common/GameRules/GameRuleManager.cpp new file mode 100644 index 0000000..0c6a780 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleManager.cpp @@ -0,0 +1,767 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\compression.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\File.h" +#include "..\..\..\Minecraft.World\compression.h" +#include "..\DLC\DLCPack.h" +#include "..\DLC\DLCLocalisationFile.h" +#include "..\DLC\DLCGameRulesFile.h" +#include "..\DLC\DLCGameRules.h" +#include "..\DLC\DLCGameRulesHeader.h" +#include "..\..\StringTable.h" +#include "ConsoleGameRules.h" +#include "GameRuleManager.h" + +WCHAR *GameRuleManager::wchTagNameA[] = +{ + L"", // eGameRuleType_Root + L"MapOptions", // eGameRuleType_LevelGenerationOptions + L"ApplySchematic", // eGameRuleType_ApplySchematic + L"GenerateStructure", // eGameRuleType_GenerateStructure + L"GenerateBox", // eGameRuleType_GenerateBox + L"PlaceBlock", // eGameRuleType_PlaceBlock + L"PlaceContainer", // eGameRuleType_PlaceContainer + L"PlaceSpawner", // eGameRuleType_PlaceSpawner + L"BiomeOverride", // eGameRuleType_BiomeOverride + L"StartFeature", // eGameRuleType_StartFeature + L"AddItem", // eGameRuleType_AddItem + L"AddEnchantment", // eGameRuleType_AddEnchantment + L"LevelRules", // eGameRuleType_LevelRules + L"NamedArea", // eGameRuleType_NamedArea + L"UseTile", // eGameRuleType_UseTileRule + L"CollectItem", // eGameRuleType_CollectItemRule + L"CompleteAll", // eGameRuleType_CompleteAllRule + L"UpdatePlayer", // eGameRuleType_UpdatePlayerRule +}; + +WCHAR *GameRuleManager::wchAttrNameA[] = +{ + L"descriptionName", // eGameRuleAttr_descriptionName + L"promptName", // eGameRuleAttr_promptName + L"dataTag", // eGameRuleAttr_dataTag + L"enchantmentId", // eGameRuleAttr_enchantmentId + L"enchantmentLevel", // eGameRuleAttr_enchantmentLevel + L"itemId", // eGameRuleAttr_itemId + L"quantity", // eGameRuleAttr_quantity + L"auxValue", // eGameRuleAttr_auxValue + L"slot", // eGameRuleAttr_slot + L"name", // eGameRuleAttr_name + L"food", // eGameRuleAttr_food + L"health", // eGameRuleAttr_health + L"tileId", // eGameRuleAttr_tileId + L"useCoords", // eGameRuleAttr_useCoords + L"seed", // eGameRuleAttr_seed + L"flatworld", // eGameRuleAttr_flatworld + L"filename", // eGameRuleAttr_filename + L"rot", // eGameRuleAttr_rot + L"data", // eGameRuleAttr_data + L"block", // eGameRuleAttr_block + L"entity", // eGameRuleAttr_entity + L"facing", // eGameRuleAttr_facing + L"edgeTile", // eGameRuleAttr_edgeTile + L"fillTile", // eGameRuleAttr_fillTile + L"skipAir", // eGameRuleAttr_skipAir + L"x", // eGameRuleAttr_x + L"x0", // eGameRuleAttr_x0 + L"x1", // eGameRuleAttr_x1 + L"y", // eGameRuleAttr_y + L"y0", // eGameRuleAttr_y0 + L"y1", // eGameRuleAttr_y1 + L"z", // eGameRuleAttr_z + L"z0", // eGameRuleAttr_z0 + L"z1", // eGameRuleAttr_z1 + L"chunkX", // eGameRuleAttr_chunkX + L"chunkZ", // eGameRuleAttr_chunkZ + L"yRot", // eGameRuleAttr_yRot + L"spawnX", // eGameRuleAttr_spawnX + L"spawnY", // eGameRuleAttr_spawnY + L"spawnZ", // eGameRuleAttr_spawnZ + L"orientation", + L"dimension", + L"topTileId", // eGameRuleAttr_topTileId + L"biomeId", // eGameRuleAttr_biomeId + L"feature", // eGameRuleAttr_feature +}; + +GameRuleManager::GameRuleManager() +{ + m_currentGameRuleDefinitions = NULL; + m_currentLevelGenerationOptions = NULL; +} + +void GameRuleManager::loadGameRules(DLCPack *pack) +{ + StringTable *strings = NULL; + + if(pack->doesPackContainFile(DLCManager::e_DLCType_LocalisationData,L"languages.loc")) + { + DLCLocalisationFile *localisationFile = (DLCLocalisationFile *)pack->getFile(DLCManager::e_DLCType_LocalisationData, L"languages.loc"); + strings = localisationFile->getStringTable(); + } + + int gameRulesCount = pack->getDLCItemsCount(DLCManager::e_DLCType_GameRulesHeader); + for(int i = 0; i < gameRulesCount; ++i) + { + DLCGameRulesHeader *dlcHeader = (DLCGameRulesHeader *)pack->getFile(DLCManager::e_DLCType_GameRulesHeader, i); + DWORD dSize; + byte *dData = dlcHeader->getData(dSize); + + LevelGenerationOptions *createdLevelGenerationOptions = new LevelGenerationOptions(); + // = loadGameRules(dData, dSize); //, strings); + + createdLevelGenerationOptions->setGrSource( dlcHeader ); + + readRuleFile(createdLevelGenerationOptions, dData, dSize, strings); + + createdLevelGenerationOptions->setSrc( LevelGenerationOptions::eSrc_fromDLC ); + + + //createdLevelGenerationOptions->setSrc( LevelGenerationOptions::eSrc_fromDLC ); + dlcHeader->lgo = createdLevelGenerationOptions; + } + + gameRulesCount = pack->getDLCItemsCount(DLCManager::e_DLCType_GameRules); + for (int i = 0; i < gameRulesCount; ++i) + { + DLCGameRulesFile *dlcFile = (DLCGameRulesFile *)pack->getFile(DLCManager::e_DLCType_GameRules, i); + + DWORD dSize; + byte *dData = dlcFile->getData(dSize); + + LevelGenerationOptions *createdLevelGenerationOptions = new LevelGenerationOptions(); + // = loadGameRules(dData, dSize); //, strings); + + createdLevelGenerationOptions->setGrSource( new JustGrSource() ); + readRuleFile(createdLevelGenerationOptions, dData, dSize, strings); + + createdLevelGenerationOptions->setSrc( LevelGenerationOptions::eSrc_tutorial ); + + //createdLevelGenerationOptions->set_DLCGameRulesFile( dlcFile ); + + createdLevelGenerationOptions->setLoadedData(); + } +} + +LevelGenerationOptions *GameRuleManager::loadGameRules(byte *dIn, UINT dSize) +{ + LevelGenerationOptions *lgo = new LevelGenerationOptions(); + lgo->setGrSource( new JustGrSource() ); + lgo->setSrc( LevelGenerationOptions::eSrc_fromSave ); + loadGameRules(lgo, dIn, dSize); + lgo->setLoadedData(); + return lgo; +} + +// 4J-JEV: Reverse of saveGameRules. +void GameRuleManager::loadGameRules(LevelGenerationOptions *lgo, byte *dIn, UINT dSize) +{ + app.DebugPrintf("GameRuleManager::LoadingGameRules:\n"); + + ByteArrayInputStream bais( byteArray(dIn,dSize) ); + DataInputStream dis(&bais); + + // Read file header. + + //dis.readInt(); // File Size + + short version = dis.readShort(); + assert( 0x1 == version ); + app.DebugPrintf("\tversion=%d.\n", version); + + for (int i = 0; i < 8; i++) dis.readByte(); + + BYTE compression_type = dis.readByte(); + + app.DebugPrintf("\tcompressionType=%d.\n", compression_type); + + UINT compr_len, decomp_len; + compr_len = dis.readInt(); + decomp_len = dis.readInt(); + + app.DebugPrintf("\tcompr_len=%d.\n\tdecomp_len=%d.\n", compr_len, decomp_len); + + + // Decompress File Body + + byteArray content(new BYTE[decomp_len], decomp_len), + compr_content(new BYTE[compr_len], compr_len); + dis.read(compr_content); + + Compression::getCompression()->SetDecompressionType( (Compression::ECompressionTypes)compression_type ); + Compression::getCompression()->DecompressLZXRLE( content.data, &content.length, + compr_content.data, compr_content.length); + Compression::getCompression()->SetDecompressionType( SAVE_FILE_PLATFORM_LOCAL ); + + dis.close(); + bais.close(); + + delete [] compr_content.data; + + ByteArrayInputStream bais2( content ); + DataInputStream dis2( &bais2 ); + + // Read StringTable. + byteArray bStringTable; + bStringTable.length = dis2.readInt(); + bStringTable.data = new BYTE[ bStringTable.length ]; + dis2.read(bStringTable); + StringTable *strings = new StringTable(bStringTable.data, bStringTable.length); + + // Read RuleFile. + byteArray bRuleFile; + bRuleFile.length = content.length - bStringTable.length; + bRuleFile.data = new BYTE[ bRuleFile.length ]; + dis2.read(bRuleFile); + + // 4J-JEV: I don't believe that the path-name is ever used. + //DLCGameRulesFile *dlcgr = new DLCGameRulesFile(L"__PLACEHOLDER__"); + //dlcgr->addData(bRuleFile.data,bRuleFile.length); + + if (readRuleFile(lgo, bRuleFile.data, bRuleFile.length, strings)) + { + // Set current gen options and ruleset. + //createdLevelGenerationOptions->setFromSaveGame(true); + lgo->setSrc(LevelGenerationOptions::eSrc_fromSave); + setLevelGenerationOptions( lgo ); + //m_currentGameRuleDefinitions = lgo->getRequiredGameRules(); + } + else + { + delete lgo; + } + + //delete [] content.data; + + // Close and return. + dis2.close(); + bais2.close(); + + return ; +} + +// 4J-JEV: Reverse of loadGameRules. +void GameRuleManager::saveGameRules(byte **dOut, UINT *dSize) +{ + if (m_currentGameRuleDefinitions == NULL && + m_currentLevelGenerationOptions == NULL) + { + app.DebugPrintf("GameRuleManager:: Nothing here to save."); + *dOut = NULL; + *dSize = 0; + return; + } + + app.DebugPrintf("GameRuleManager::saveGameRules:\n"); + + // Initialise output stream. + ByteArrayOutputStream baos; + DataOutputStream dos(&baos); + + // Write header. + + // VERSION NUMBER + dos.writeShort( 0x1 ); // version_number + + // Write 8 bytes of empty space in case we need them later. + // Mainly useful for the ones we save embedded in game saves. + for (UINT i = 0; i < 8; i++) + dos.writeByte(0x0); + + dos.writeByte(APPROPRIATE_COMPRESSION_TYPE); // m_compressionType + + // -- START COMPRESSED -- // + ByteArrayOutputStream compr_baos; + DataOutputStream compr_dos(&compr_baos); + + if (m_currentGameRuleDefinitions == NULL) + { + compr_dos.writeInt( 0 ); // numStrings for StringTable + compr_dos.writeInt( version_number ); + compr_dos.writeByte(Compression::eCompressionType_None); // compression type + for (int i=0; i<2; i++) compr_dos.writeByte(0x0); // Padding. + compr_dos.writeInt( 0 ); // StringLookup.length + compr_dos.writeInt( 0 ); // SchematicFiles.length + compr_dos.writeInt( 0 ); // XmlObjects.length + } + else + { + StringTable *st = m_currentGameRuleDefinitions->getStringTable(); + + if (st == NULL) + { + app.DebugPrintf("GameRuleManager::saveGameRules: StringTable == NULL!"); + } + else + { + // Write string table. + byteArray stba; + m_currentGameRuleDefinitions->getStringTable()->getData(&stba.data, &stba.length); + compr_dos.writeInt( stba.length ); + compr_dos.write( stba ); + + // Write game rule file to second + // buffer and generate string lookup. + writeRuleFile(&compr_dos); + } + } + + // Compress compr_dos and write to dos. + byteArray compr_ba(new BYTE[ compr_baos.buf.length ], compr_baos.buf.length); + Compression::getCompression()->CompressLZXRLE( compr_ba.data, &compr_ba.length, + compr_baos.buf.data, compr_baos.buf.length ); + + app.DebugPrintf("\tcompr_ba.length=%d.\n\tcompr_baos.buf.length=%d.\n", + compr_ba.length, compr_baos.buf.length ); + + dos.writeInt( compr_ba.length ); // Write length + dos.writeInt( compr_baos.buf.length ); + dos.write(compr_ba); + + delete [] compr_ba.data; + + compr_dos.close(); + compr_baos.close(); + // -- END COMPRESSED -- // + + // return + *dSize = baos.buf.length; + *dOut = baos.buf.data; + + baos.buf.data = NULL; + + dos.close(); baos.close(); +} + +// 4J-JEV: Reverse of readRuleFile. +void GameRuleManager::writeRuleFile(DataOutputStream *dos) +{ + // Write Header + dos->writeShort(version_number); // Version number. + dos->writeByte(Compression::eCompressionType_None); // compression type + for (int i=0; i<8; i++) dos->writeBoolean(false); // Padding. + + // Write string lookup. + int numStrings = ConsoleGameRules::eGameRuleType_Count + ConsoleGameRules::eGameRuleAttr_Count; + dos->writeInt(numStrings); + for (int i = 0; i < ConsoleGameRules::eGameRuleType_Count; i++) dos->writeUTF( wchTagNameA[i] ); + for (int i = 0; i < ConsoleGameRules::eGameRuleAttr_Count; i++) dos->writeUTF( wchAttrNameA[i] ); + + // Write schematic files. + unordered_map *files; + files = getLevelGenerationOptions()->getUnfinishedSchematicFiles(); + dos->writeInt( files->size() ); + for (AUTO_VAR(it, files->begin()); it != files->end(); it++) + { + wstring filename = it->first; + ConsoleSchematicFile *file = it->second; + + ByteArrayOutputStream fileBaos; + DataOutputStream fileDos(&fileBaos); + file->save(&fileDos); + + dos->writeUTF(filename); + //dos->writeInt(file->m_data.length); + dos->writeInt(fileBaos.buf.length); + dos->write((byteArray)fileBaos.buf); + + fileDos.close(); fileBaos.close(); + } + + // Write xml objects. + dos->writeInt( 2 ); // numChildren + m_currentLevelGenerationOptions->write(dos); + m_currentGameRuleDefinitions->write(dos); +} + +bool GameRuleManager::readRuleFile(LevelGenerationOptions *lgo, byte *dIn, UINT dSize, StringTable *strings) //(DLCGameRulesFile *dlcFile, StringTable *strings) +{ + bool levelGenAdded = false; + bool gameRulesAdded = false; + LevelGenerationOptions *levelGenerator = lgo;//new LevelGenerationOptions(); + LevelRuleset *gameRules = new LevelRuleset(); + + //DWORD dwLen = 0; + //PBYTE pbData = dlcFile->getData(dwLen); + //byteArray data(pbData,dwLen); + + byteArray data(dIn, dSize); + ByteArrayInputStream bais(data); + DataInputStream dis(&bais); + + // Read File. + + // version_number + __int64 version = dis.readShort(); + unsigned char compressionType = 0; + if(version == 0) + { + for (int i = 0; i < 14; i++) dis.readByte(); // Read padding. + } + else + { + compressionType = dis.readByte(); + + // Read the spare bytes we inserted for future use + for(int i = 0; i < 8; ++i) dis.readBoolean(); + } + + ByteArrayInputStream *contentBais = NULL; + DataInputStream *contentDis = NULL; + + if(compressionType == Compression::eCompressionType_None) + { + // No compression + // No need to read buffer size, as we can read the stream as it is; + app.DebugPrintf("De-compressing game rules with: None\n"); + contentDis = &dis; + } + else + { + unsigned int uncompressedSize = dis.readInt(); + unsigned int compressedSize = dis.readInt(); + byteArray compressedBuffer(compressedSize); + dis.read(compressedBuffer); + + byteArray decompressedBuffer = byteArray(uncompressedSize); + + switch(compressionType) + { + case Compression::eCompressionType_None: + memcpy(decompressedBuffer.data, compressedBuffer.data, uncompressedSize); + break; + + case Compression::eCompressionType_RLE: + app.DebugPrintf("De-compressing game rules with: RLE\n"); + Compression::getCompression()->Decompress( decompressedBuffer.data, &decompressedBuffer.length, compressedBuffer.data, compressedSize); + break; + + default: + app.DebugPrintf("De-compressing game rules."); +#ifndef _CONTENT_PACKAGE + assert( compressionType == APPROPRIATE_COMPRESSION_TYPE ); +#endif + // 4J-JEV: DecompressLZXRLE uses the correct platform specific compression type. (need to assert that the data is compressed with it though). + Compression::getCompression()->DecompressLZXRLE(decompressedBuffer.data, &decompressedBuffer.length, compressedBuffer.data, compressedSize); + break; +/* 4J-JEV: + Each platform has only 1 method of compression, 'compression.h' file deals with it. + + case Compression::eCompressionType_LZXRLE: + app.DebugPrintf("De-compressing game rules with: LZX+RLE\n"); + Compression::getCompression()->DecompressLZXRLE( decompressedBuffer.data, &uncompressedSize, compressedBuffer.data, compressedSize); + break; + default: + app.DebugPrintf("Invalid compression type %d found\n", compressionType); + __debugbreak(); + + delete [] compressedBuffer.data; delete [] decompressedBuffer.data; + dis.close(); bais.reset(); + + if(!gameRulesAdded) delete gameRules; + return false; + */ + }; + + delete [] compressedBuffer.data; + + contentBais = new ByteArrayInputStream(decompressedBuffer); + contentDis = new DataInputStream(contentBais); + } + + // string lookup. + UINT numStrings = contentDis->readInt(); + vector tagsAndAtts; + for (UINT i = 0; i < numStrings; i++) + tagsAndAtts.push_back( contentDis->readUTF() ); + + unordered_map tagIdMap; + for(int type = (int)ConsoleGameRules::eGameRuleType_Root; type < (int)ConsoleGameRules::eGameRuleType_Count; ++type) + { + for(UINT i = 0; i < numStrings; ++i) + { + if(tagsAndAtts[i].compare(wchTagNameA[type]) == 0) + { + tagIdMap.insert( unordered_map::value_type(i, (ConsoleGameRules::EGameRuleType)type) ); + break; + } + } + } + + // 4J-JEV: TODO: As yet unused. + /* + unordered_map attrIdMap; + for(int attr = (int)ConsoleGameRules::eGameRuleAttr_descriptionName; attr < (int)ConsoleGameRules::eGameRuleAttr_Count; ++attr) + { + for (UINT i = 0; i < numStrings; i++) + { + if (tagsAndAtts[i].compare(wchAttrNameA[attr]) == 0) + { + tagIdMap.insert( unordered_map::value_type(i , (ConsoleGameRules::EGameRuleAttr)attr) ); + break; + } + } + }*/ + + // subfile + UINT numFiles = contentDis->readInt(); + for (UINT i = 0; i < numFiles; i++) + { + wstring sFilename = contentDis->readUTF(); + int length = contentDis->readInt(); + byteArray ba( length ); + + contentDis->read(ba); + + levelGenerator->loadSchematicFile(sFilename, ba.data, ba.length); + + } + + LEVEL_GEN_ID lgoID = LEVEL_GEN_ID_NULL; + + // xml objects + UINT numObjects = contentDis->readInt(); + for(UINT i = 0; i < numObjects; ++i) + { + int tagId = contentDis->readInt(); + ConsoleGameRules::EGameRuleType tagVal = ConsoleGameRules::eGameRuleType_Invalid; + AUTO_VAR(it,tagIdMap.find(tagId)); + if(it != tagIdMap.end()) tagVal = it->second; + + GameRuleDefinition *rule = NULL; + + if(tagVal == ConsoleGameRules::eGameRuleType_LevelGenerationOptions) + { + rule = levelGenerator; + levelGenAdded = true; + //m_levelGenerators.addLevelGenerator(L"",levelGenerator); + lgoID = addLevelGenerationOptions(levelGenerator); + levelGenerator->loadStringTable(strings); + } + else if(tagVal == ConsoleGameRules::eGameRuleType_LevelRules) + { + rule = gameRules; + gameRulesAdded = true; + m_levelRules.addLevelRule(L"",gameRules); + levelGenerator->setRequiredGameRules(gameRules); + gameRules->loadStringTable(strings); + } + + readAttributes(contentDis, &tagsAndAtts, rule); + readChildren(contentDis, &tagsAndAtts, &tagIdMap, rule); + } + + if(compressionType != 0) + { + // Not default + contentDis->close(); + if(contentBais != NULL) delete contentBais; + delete contentDis; + } + + dis.close(); + bais.reset(); + + //if(!levelGenAdded) { delete levelGenerator; levelGenerator = NULL; } + if(!gameRulesAdded) delete gameRules; + + return true; + //return levelGenerator; +} + +LevelGenerationOptions *GameRuleManager::readHeader(DLCGameRulesHeader *grh) +{ + LevelGenerationOptions *out = + new LevelGenerationOptions(); + + + out->setSrc(LevelGenerationOptions::eSrc_fromDLC); + out->setGrSource(grh); + addLevelGenerationOptions(out); + + return out; +} + +void GameRuleManager::readAttributes(DataInputStream *dis, vector *tagsAndAtts, GameRuleDefinition *rule) +{ + int numAttrs = dis->readInt(); + for (UINT att = 0; att < numAttrs; ++att) + { + int attID = dis->readInt(); + wstring value = dis->readUTF(); + + if(rule != NULL) rule->addAttribute(tagsAndAtts->at(attID),value); + } +} + +void GameRuleManager::readChildren(DataInputStream *dis, vector *tagsAndAtts, unordered_map *tagIdMap, GameRuleDefinition *rule) +{ + int numChildren = dis->readInt(); + for(UINT child = 0; child < numChildren; ++child) + { + int tagId = dis->readInt(); + ConsoleGameRules::EGameRuleType tagVal = ConsoleGameRules::eGameRuleType_Invalid; + AUTO_VAR(it,tagIdMap->find(tagId)); + if(it != tagIdMap->end()) tagVal = it->second; + + GameRuleDefinition *childRule = NULL; + if(rule != NULL) childRule = rule->addChild(tagVal); + + readAttributes(dis,tagsAndAtts,childRule); + readChildren(dis,tagsAndAtts,tagIdMap,childRule); + } +} + +void GameRuleManager::processSchematics(LevelChunk *levelChunk) +{ + if(getLevelGenerationOptions() != NULL) + { + LevelGenerationOptions *levelGenOptions = getLevelGenerationOptions(); + levelGenOptions->processSchematics(levelChunk); + } +} + +void GameRuleManager::processSchematicsLighting(LevelChunk *levelChunk) +{ + if(getLevelGenerationOptions() != NULL) + { + LevelGenerationOptions *levelGenOptions = getLevelGenerationOptions(); + levelGenOptions->processSchematicsLighting(levelChunk); + } +} + +void GameRuleManager::loadDefaultGameRules() +{ +#ifdef _XBOX +#ifdef _TU_BUILD + wstring fileRoot = L"UPDATE:\\res\\GameRules\\Tutorial.pck"; +#else + wstring fileRoot = L"GAME:\\res\\TitleUpdate\\GameRules\\Tutorial.pck"; +#endif + File packedTutorialFile(fileRoot); + if(loadGameRulesPack(&packedTutorialFile)) + { + m_levelGenerators.getLevelGenerators()->at(0)->setWorldName(app.GetString(IDS_PLAY_TUTORIAL)); + //m_levelGenerators.getLevelGenerators()->at(0)->setDefaultSaveName(L"Tutorial"); + m_levelGenerators.getLevelGenerators()->at(0)->setDefaultSaveName(app.GetString(IDS_TUTORIALSAVENAME)); + } + +#ifndef _CONTENT_PACKAGE + // 4J Stu - Remove these just now + //File testRulesPath(L"GAME:\\GameRules"); + //vector *packFiles = testRulesPath.listFiles(); + + //for(AUTO_VAR(it,packFiles->begin()); it != packFiles->end(); ++it) + //{ + // loadGameRulesPack(*it); + //} + //delete packFiles; +#endif + +#else // _XBOX + + wstring fpTutorial = L"Tutorial.pck"; + if(app.getArchiveFileSize(fpTutorial) >= 0) + { + DLCPack *pack = new DLCPack(L"",0xffffffff); + DWORD dwFilesProcessed = 0; + if ( app.m_dlcManager.readDLCDataFile(dwFilesProcessed,fpTutorial,pack,true) ) + { + app.m_dlcManager.addPack(pack); + m_levelGenerators.getLevelGenerators()->at(0)->setWorldName(app.GetString(IDS_PLAY_TUTORIAL)); + m_levelGenerators.getLevelGenerators()->at(0)->setDefaultSaveName(app.GetString(IDS_TUTORIALSAVENAME)); + } + else delete pack; + } + /*StringTable *strings = new StringTable(baStrings.data, baStrings.length); + LevelGenerationOptions *lgo = new LevelGenerationOptions(); + lgo->setGrSource( new JustGrSource() ); + lgo->setSrc( LevelGenerationOptions::eSrc_tutorial ); + readRuleFile(lgo, tutorial.data, tutorial.length, strings); + lgo->setLoadedData();*/ + +#endif +} + +bool GameRuleManager::loadGameRulesPack(File *path) +{ + bool success = false; +#ifdef _XBOX + if(path->exists()) + { + DLCPack *pack = new DLCPack(L"",0xffffffff); + DWORD dwFilesProcessed = 0; + if( app.m_dlcManager.readDLCDataFile(dwFilesProcessed, path->getPath(),pack)) + { + app.m_dlcManager.addPack(pack); + success = true; + } + else + { + delete pack; + } + } +#endif + return success; +} + +void GameRuleManager::setLevelGenerationOptions(LevelGenerationOptions *levelGen) +{ + m_currentGameRuleDefinitions = NULL; + m_currentLevelGenerationOptions = levelGen; + + if(m_currentLevelGenerationOptions != NULL && m_currentLevelGenerationOptions->requiresGameRules() ) + { + m_currentGameRuleDefinitions = m_currentLevelGenerationOptions->getRequiredGameRules(); + } + + if(m_currentLevelGenerationOptions != NULL) + m_currentLevelGenerationOptions->reset_start(); +} + +LPCWSTR GameRuleManager::GetGameRulesString(const wstring &key) +{ + if(m_currentGameRuleDefinitions != NULL && !key.empty() ) + { + return m_currentGameRuleDefinitions->getString(key); + } + else + { + return L""; + } +} + +LEVEL_GEN_ID GameRuleManager::addLevelGenerationOptions(LevelGenerationOptions *lgo) +{ + vector *lgs = m_levelGenerators.getLevelGenerators(); + + for (int i = 0; isize(); i++) + if (lgs->at(i) == lgo) + return i; + + lgs->push_back(lgo); + return lgs->size() - 1; +} + +void GameRuleManager::unloadCurrentGameRules() +{ + if (m_currentLevelGenerationOptions != NULL) + { + if (m_currentGameRuleDefinitions != NULL + && m_currentLevelGenerationOptions->isFromSave()) + m_levelRules.removeLevelRule( m_currentGameRuleDefinitions ); + + if (m_currentLevelGenerationOptions->isFromSave()) + { + m_levelGenerators.removeLevelGenerator( m_currentLevelGenerationOptions ); + + delete m_currentLevelGenerationOptions; + } + else if (m_currentLevelGenerationOptions->isFromDLC()) + { + m_currentLevelGenerationOptions->reset_finish(); + } + } + + m_currentGameRuleDefinitions = NULL; + m_currentLevelGenerationOptions = NULL; +} diff --git a/Minecraft.Client/Common/GameRules/GameRuleManager.h b/Minecraft.Client/Common/GameRules/GameRuleManager.h new file mode 100644 index 0000000..e9e983b --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRuleManager.h @@ -0,0 +1,80 @@ +#pragma once +using namespace std; + +#include "LevelGenerators.h" +#include "LevelRules.h" +class LevelGenerationOptions; +class RootGameRulesDefinition; +class LevelChunk; +class DLCPack; +class DLCGameRulesFile; +class DLCGameRulesHeader; +class StringTable; +class GameRuleDefinition; +class DataInputStream; +class DataOutputStream; +class WstringLookup; + +#define GAME_RULE_SAVENAME L"requiredGameRules.grf" + +// 4J-JEV: +#define LEVEL_GEN_ID int +#define LEVEL_GEN_ID_NULL 0 + +class GameRuleManager +{ +public: + static WCHAR *wchTagNameA[ConsoleGameRules::eGameRuleType_Count]; + static WCHAR *wchAttrNameA[ConsoleGameRules::eGameRuleAttr_Count]; + + static const short version_number = 2; + +private: + LevelGenerationOptions *m_currentLevelGenerationOptions; + LevelRuleset *m_currentGameRuleDefinitions; + LevelGenerators m_levelGenerators; + LevelRules m_levelRules; + +public: + GameRuleManager(); + + void loadGameRules(DLCPack *); + + LevelGenerationOptions *loadGameRules(byte *dIn, UINT dSize); + void loadGameRules(LevelGenerationOptions *lgo, byte *dIn, UINT dSize); + + void saveGameRules(byte **dOut, UINT *dSize); + +private: + LevelGenerationOptions *readHeader(DLCGameRulesHeader *grh); + + void writeRuleFile(DataOutputStream *dos); + +public: + bool readRuleFile(LevelGenerationOptions *lgo, byte *dIn, UINT dSize, StringTable *strings); //(DLCGameRulesFile *dlcFile, StringTable *strings); + +private: + void readAttributes(DataInputStream *dis, vector *tagsAndAtts, GameRuleDefinition *rule); + void readChildren(DataInputStream *dis, vector *tagsAndAtts, unordered_map *tagIdMap, GameRuleDefinition *rule); + +public: + void processSchematics(LevelChunk *levelChunk); + void processSchematicsLighting(LevelChunk *levelChunk); + void loadDefaultGameRules(); + +private: + bool loadGameRulesPack(File *path); + + LEVEL_GEN_ID addLevelGenerationOptions(LevelGenerationOptions *); + +public: + vector *getLevelGenerators() { return m_levelGenerators.getLevelGenerators(); } + void setLevelGenerationOptions(LevelGenerationOptions *levelGen); + LevelRuleset *getGameRuleDefinitions() { return m_currentGameRuleDefinitions; } + LevelGenerationOptions *getLevelGenerationOptions() { return m_currentLevelGenerationOptions; } + LPCWSTR GetGameRulesString(const wstring &key); + + // 4J-JEV: + // Properly cleans-up and unloads the current set of gameRules. + void unloadCurrentGameRules(); +}; diff --git a/Minecraft.Client/Common/GameRules/GameRulesInstance.h b/Minecraft.Client/Common/GameRules/GameRulesInstance.h new file mode 100644 index 0000000..064e086 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/GameRulesInstance.h @@ -0,0 +1,24 @@ +#pragma once +using namespace std; +#include +#include "GameRule.h" + +class GameRuleDefinition; + +// The game rule manager belongs to a player/server or other object, and maintains their current state for each of +// the rules that apply to them +class GameRulesInstance : public GameRule +{ +public: + // These types are used by the GameRuleDefinition to know which rules to add to this GameRulesInstance + enum EGameRulesInstanceType + { + eGameRulesInstanceType_ServerPlayer, + eGameRulesInstanceType_Server, + eGameRulesInstanceType_Count + }; + +public: + GameRulesInstance(GameRuleDefinition *definition, Connection *connection) : GameRule(definition,connection) {} + // Functions for all the hooks should go here +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp new file mode 100644 index 0000000..717b066 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.cpp @@ -0,0 +1,514 @@ +#include "stdafx.h" + +#include + +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\Pos.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.chunk.h" +#include "..\..\StringTable.h" +#include "LevelGenerationOptions.h" +#include "ConsoleGameRules.h" + +JustGrSource::JustGrSource() +{ + m_displayName = L"Default_DisplayName"; + m_worldName= L"Default_WorldName"; + m_defaultSaveName = L"Default_DefaultSaveName"; + m_bRequiresTexturePack = false; + m_requiredTexturePackId = 0; + m_grfPath = L"__NO_GRF_PATH__"; + m_bRequiresBaseSave = false; +} + +bool JustGrSource::requiresTexturePack() {return m_bRequiresTexturePack;} +UINT JustGrSource::getRequiredTexturePackId() {return m_requiredTexturePackId;} +wstring JustGrSource::getDefaultSaveName() {return m_defaultSaveName;} +LPCWSTR JustGrSource::getWorldName() {return m_worldName.c_str();} +LPCWSTR JustGrSource::getDisplayName() {return m_displayName.c_str();} +wstring JustGrSource::getGrfPath() {return m_grfPath;} +bool JustGrSource::requiresBaseSave() { return m_bRequiresBaseSave; }; +wstring JustGrSource::getBaseSavePath() { return m_baseSavePath; }; + +void JustGrSource::setRequiresTexturePack(bool x) {m_bRequiresTexturePack = x;} +void JustGrSource::setRequiredTexturePackId(UINT x) {m_requiredTexturePackId = x;} +void JustGrSource::setDefaultSaveName(const wstring &x) {m_defaultSaveName = x;} +void JustGrSource::setWorldName(const wstring &x) {m_worldName = x;} +void JustGrSource::setDisplayName(const wstring &x) {m_displayName = x;} +void JustGrSource::setGrfPath(const wstring &x) {m_grfPath = x;} +void JustGrSource::setBaseSavePath(const wstring &x) { m_baseSavePath = x; m_bRequiresBaseSave = true; } + +bool JustGrSource::ready() { return true; } + +LevelGenerationOptions::LevelGenerationOptions() +{ + m_spawnPos = NULL; + m_stringTable = NULL; + + m_hasLoadedData = false; + + m_seed = 0; + m_useFlatWorld = false; + m_bHaveMinY = false; + m_minY = INT_MAX; + m_bRequiresGameRules = false; + + m_pbBaseSaveData = NULL; + m_dwBaseSaveSize = 0; +} + +LevelGenerationOptions::~LevelGenerationOptions() +{ + clearSchematics(); + if(m_spawnPos != NULL) delete m_spawnPos; + for(AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end(); ++it) + { + delete *it; + } + for(AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); ++it) + { + delete *it; + } + + for(AUTO_VAR(it, m_biomeOverrides.begin()); it != m_biomeOverrides.end(); ++it) + { + delete *it; + } + + for(AUTO_VAR(it, m_features.begin()); it != m_features.end(); ++it) + { + delete *it; + } + + if (m_stringTable) + if (!isTutorial()) + delete m_stringTable; + + if (isFromSave()) delete m_pSrc; +} + +ConsoleGameRules::EGameRuleType LevelGenerationOptions::getActionType() { return ConsoleGameRules::eGameRuleType_LevelGenerationOptions; } + +void LevelGenerationOptions::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnX); + dos->writeUTF(_toString(m_spawnPos->x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnY); + dos->writeUTF(_toString(m_spawnPos->y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnZ); + dos->writeUTF(_toString(m_spawnPos->z)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_seed); + dos->writeUTF(_toString(m_seed)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_flatworld); + dos->writeUTF(_toString(m_useFlatWorld)); +} + +void LevelGenerationOptions::getChildren(vector *children) +{ + GameRuleDefinition::getChildren(children); + + vector used_schematics; + for (AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end(); it++) + if ( !(*it)->isComplete() ) + used_schematics.push_back( *it ); + + for(AUTO_VAR(it, m_structureRules.begin()); it!=m_structureRules.end(); it++) + children->push_back( *it ); + for(AUTO_VAR(it, used_schematics.begin()); it!=used_schematics.end(); it++) + children->push_back( *it ); + for(AUTO_VAR(it, m_biomeOverrides.begin()); it != m_biomeOverrides.end(); ++it) + children->push_back( *it ); + for(AUTO_VAR(it, m_features.begin()); it != m_features.end(); ++it) + children->push_back( *it ); +} + +GameRuleDefinition *LevelGenerationOptions::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_ApplySchematic) + { + rule = new ApplySchematicRuleDefinition(this); + m_schematicRules.push_back((ApplySchematicRuleDefinition *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_GenerateStructure) + { + rule = new ConsoleGenerateStructure(); + m_structureRules.push_back((ConsoleGenerateStructure *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_BiomeOverride) + { + rule = new BiomeOverride(); + m_biomeOverrides.push_back((BiomeOverride *)rule); + } + else if(ruleType == ConsoleGameRules::eGameRuleType_StartFeature) + { + rule = new StartFeature(); + m_features.push_back((StartFeature *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"LevelGenerationOptions: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void LevelGenerationOptions::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"seed") == 0) + { + m_seed = _fromString<__int64>(attributeValue); + app.DebugPrintf("LevelGenerationOptions: Adding parameter m_seed=%I64d\n",m_seed); + } + else if(attributeName.compare(L"spawnX") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString(attributeValue); + m_spawnPos->x = value; + app.DebugPrintf("LevelGenerationOptions: Adding parameter spawnX=%d\n",value); + } + else if(attributeName.compare(L"spawnY") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString(attributeValue); + m_spawnPos->y = value; + app.DebugPrintf("LevelGenerationOptions: Adding parameter spawnY=%d\n",value); + } + else if(attributeName.compare(L"spawnZ") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString(attributeValue); + m_spawnPos->z = value; + app.DebugPrintf("LevelGenerationOptions: Adding parameter spawnZ=%d\n",value); + } + else if(attributeName.compare(L"flatworld") == 0) + { + if(attributeValue.compare(L"true") == 0) m_useFlatWorld = true; + app.DebugPrintf("LevelGenerationOptions: Adding parameter flatworld=%s\n",m_useFlatWorld?"TRUE":"FALSE"); + } + else if(attributeName.compare(L"saveName") == 0) + { + wstring string(getString(attributeValue)); + if(!string.empty()) setDefaultSaveName( string ); + else setDefaultSaveName( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter saveName=%ls\n", getDefaultSaveName().c_str()); + } + else if(attributeName.compare(L"worldName") == 0) + { + wstring string(getString(attributeValue)); + if(!string.empty()) setWorldName( string ); + else setWorldName( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter worldName=%ls\n", getWorldName()); + } + else if(attributeName.compare(L"displayName") == 0) + { + wstring string(getString(attributeValue)); + if(!string.empty()) setDisplayName( string ); + else setDisplayName( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter displayName=%ls\n", getDisplayName()); + } + else if(attributeName.compare(L"texturePackId") == 0) + { + setRequiredTexturePackId( _fromString(attributeValue) ); + setRequiresTexturePack( true ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter texturePackId=%0x\n", getRequiredTexturePackId()); + } + else if(attributeName.compare(L"isTutorial") == 0) + { + if(attributeValue.compare(L"true") == 0) setSrc(eSrc_tutorial); + app.DebugPrintf("LevelGenerationOptions: Adding parameter isTutorial=%s\n",isTutorial()?"TRUE":"FALSE"); + } + else if(attributeName.compare(L"baseSaveName") == 0) + { + setBaseSavePath( attributeValue ); + app.DebugPrintf("LevelGenerationOptions: Adding parameter baseSaveName=%ls\n", getBaseSavePath().c_str()); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +void LevelGenerationOptions::processSchematics(LevelChunk *chunk) +{ + PIXBeginNamedEvent(0,"Processing schematics for chunk (%d,%d)", chunk->x, chunk->z); + AABB *chunkBox = AABB::newTemp(chunk->x*16,0,chunk->z*16,chunk->x*16 + 16,Level::maxBuildHeight,chunk->z*16 + 16); + for( AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + rule->processSchematic(chunkBox, chunk); + } + + int cx = (chunk->x << 4); + int cz = (chunk->z << 4); + + for( AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); it++ ) + { + ConsoleGenerateStructure *structureStart = *it; + + if (structureStart->getBoundingBox()->intersects(cx, cz, cx + 15, cz + 15)) + { + BoundingBox *bb = new BoundingBox(cx, cz, cx + 15, cz + 15); + structureStart->postProcess(chunk->level, NULL, bb); + delete bb; + } + } + PIXEndNamedEvent(); +} + +void LevelGenerationOptions::processSchematicsLighting(LevelChunk *chunk) +{ + PIXBeginNamedEvent(0,"Processing schematics (lighting) for chunk (%d,%d)", chunk->x, chunk->z); + AABB *chunkBox = AABB::newTemp(chunk->x*16,0,chunk->z*16,chunk->x*16 + 16,Level::maxBuildHeight,chunk->z*16 + 16); + for( AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + rule->processSchematicLighting(chunkBox, chunk); + } + PIXEndNamedEvent(); +} + +bool LevelGenerationOptions::checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1) +{ + PIXBeginNamedEvent(0,"Check Intersects"); + + // As an optimisation, we can quickly discard things below a certain y which makes most ore checks faster due to + // a) ores generally being below ground/sea level and b) tutorial world additions generally being above ground/sea level + if(!m_bHaveMinY) + { + for(AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + int minY = rule->getMinY(); + if(minY < m_minY) m_minY = minY; + } + + for( AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); it++ ) + { + ConsoleGenerateStructure *structureStart = *it; + int minY = structureStart->getMinY(); + if(minY < m_minY) m_minY = minY; + } + + m_bHaveMinY = true; + } + + // 4J Stu - We DO NOT intersect if our upper bound is below the lower bound for all schematics + if( y1 < m_minY ) return false; + + bool intersects = false; + for(AUTO_VAR(it, m_schematicRules.begin()); it != m_schematicRules.end();++it) + { + ApplySchematicRuleDefinition *rule = *it; + intersects = rule->checkIntersects(x0,y0,z0,x1,y1,z1); + if(intersects) break; + } + + if(!intersects) + { + for( AUTO_VAR(it, m_structureRules.begin()); it != m_structureRules.end(); it++ ) + { + ConsoleGenerateStructure *structureStart = *it; + intersects = structureStart->checkIntersects(x0,y0,z0,x1,y1,z1); + if(intersects) break; + } + } + PIXEndNamedEvent(); + return intersects; +} + +void LevelGenerationOptions::clearSchematics() +{ + for(AUTO_VAR(it, m_schematics.begin()); it != m_schematics.end(); ++it) + { + delete it->second; + } + m_schematics.clear(); +} + +ConsoleSchematicFile *LevelGenerationOptions::loadSchematicFile(const wstring &filename, PBYTE pbData, DWORD dwLen) +{ + // If we have already loaded this, just return + AUTO_VAR(it, m_schematics.find(filename)); + if(it != m_schematics.end()) + { +#ifndef _CONTENT_PACKAGE + wprintf(L"We have already loaded schematic file %ls\n", filename.c_str() ); +#endif + it->second->incrementRefCount(); + return it->second; + } + + ConsoleSchematicFile *schematic = NULL; + byteArray data(pbData,dwLen); + ByteArrayInputStream bais(data); + DataInputStream dis(&bais); + schematic = new ConsoleSchematicFile(); + schematic->load(&dis); + m_schematics[filename] = schematic; + bais.reset(); + return schematic; +} + +ConsoleSchematicFile *LevelGenerationOptions::getSchematicFile(const wstring &filename) +{ + ConsoleSchematicFile *schematic = NULL; + // If we have already loaded this, just return + AUTO_VAR(it, m_schematics.find(filename)); + if(it != m_schematics.end()) + { + schematic = it->second; + } + return schematic; +} + +void LevelGenerationOptions::releaseSchematicFile(const wstring &filename) +{ + // 4J Stu - We don't want to delete them when done, but probably want to keep a set of active schematics for the current world + //AUTO_VAR(it, m_schematics.find(filename)); + //if(it != m_schematics.end()) + //{ + // ConsoleSchematicFile *schematic = it->second; + // schematic->decrementRefCount(); + // if(schematic->shouldDelete()) + // { + // delete schematic; + // m_schematics.erase(it); + // } + //} +} + +void LevelGenerationOptions::loadStringTable(StringTable *table) +{ + m_stringTable = table; +} + +LPCWSTR LevelGenerationOptions::getString(const wstring &key) +{ + if(m_stringTable == NULL) + { + return L""; + } + else + { + return m_stringTable->getString(key); + } +} + +void LevelGenerationOptions::getBiomeOverride(int biomeId, BYTE &tile, BYTE &topTile) +{ + for(AUTO_VAR(it, m_biomeOverrides.begin()); it != m_biomeOverrides.end(); ++it) + { + BiomeOverride *bo = *it; + if(bo->isBiome(biomeId)) + { + bo->getTileValues(tile,topTile); + break; + } + } +} + +bool LevelGenerationOptions::isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature) +{ + bool isFeature = false; + + for(AUTO_VAR(it, m_features.begin()); it != m_features.end(); ++it) + { + StartFeature *sf = *it; + if(sf->isFeatureChunk(chunkX, chunkZ, feature)) + { + isFeature = true; + break; + } + } + return isFeature; +} + +unordered_map *LevelGenerationOptions::getUnfinishedSchematicFiles() +{ + // Clean schematic rules. + unordered_set usedFiles = unordered_set(); + for (AUTO_VAR(it, m_schematicRules.begin()); it!=m_schematicRules.end(); it++) + if ( !(*it)->isComplete() ) + usedFiles.insert( (*it)->getSchematicName() ); + + // Clean schematic files. + unordered_map *out + = new unordered_map(); + for (AUTO_VAR(it, usedFiles.begin()); it!=usedFiles.end(); it++) + out->insert( pair(*it, getSchematicFile(*it)) ); + + return out; +} + +void LevelGenerationOptions::reset_start() +{ + for ( AUTO_VAR( it, m_schematicRules.begin()); + it != m_schematicRules.end(); + it++ ) + { + (*it)->reset(); + } +} + +void LevelGenerationOptions::reset_finish() +{ + //if (m_spawnPos) { delete m_spawnPos; m_spawnPos = NULL; } + //if (m_stringTable) { delete m_stringTable; m_stringTable = NULL; } + + if (isFromDLC()) + { + m_hasLoadedData = false; + } +} + + +GrSource *LevelGenerationOptions::info() { return m_pSrc; } +void LevelGenerationOptions::setSrc(eSrc src) { m_src = src; } +LevelGenerationOptions::eSrc LevelGenerationOptions::getSrc() { return m_src; } + +bool LevelGenerationOptions::isTutorial() { return getSrc() == eSrc_tutorial; } +bool LevelGenerationOptions::isFromSave() { return getSrc() == eSrc_fromSave; } +bool LevelGenerationOptions::isFromDLC() { return getSrc() == eSrc_fromDLC; } + +bool LevelGenerationOptions::requiresTexturePack() { return info()->requiresTexturePack(); } +UINT LevelGenerationOptions::getRequiredTexturePackId() { return info()->getRequiredTexturePackId(); } +wstring LevelGenerationOptions::getDefaultSaveName() { return info()->getDefaultSaveName(); } +LPCWSTR LevelGenerationOptions::getWorldName() { return info()->getWorldName(); } +LPCWSTR LevelGenerationOptions::getDisplayName() { return info()->getDisplayName(); } +wstring LevelGenerationOptions::getGrfPath() { return info()->getGrfPath(); } +bool LevelGenerationOptions::requiresBaseSave() { return info()->requiresBaseSave(); } +wstring LevelGenerationOptions::getBaseSavePath() { return info()->getBaseSavePath(); } + +void LevelGenerationOptions::setGrSource(GrSource *grs) { m_pSrc = grs; } + +void LevelGenerationOptions::setRequiresTexturePack(bool x) { info()->setRequiresTexturePack(x); } +void LevelGenerationOptions::setRequiredTexturePackId(UINT x) { info()->setRequiredTexturePackId(x); } +void LevelGenerationOptions::setDefaultSaveName(const wstring &x) { info()->setDefaultSaveName(x); } +void LevelGenerationOptions::setWorldName(const wstring &x) { info()->setWorldName(x); } +void LevelGenerationOptions::setDisplayName(const wstring &x) { info()->setDisplayName(x); } +void LevelGenerationOptions::setGrfPath(const wstring &x) { info()->setGrfPath(x); } +void LevelGenerationOptions::setBaseSavePath(const wstring &x) { info()->setBaseSavePath(x); } + +bool LevelGenerationOptions::ready() { return info()->ready(); } + +void LevelGenerationOptions::setBaseSaveData(PBYTE pbData, DWORD dwSize) { m_pbBaseSaveData = pbData; m_dwBaseSaveSize = dwSize; } +PBYTE LevelGenerationOptions::getBaseSaveData(DWORD &size) { size = m_dwBaseSaveSize; return m_pbBaseSaveData; } +bool LevelGenerationOptions::hasBaseSaveData() { return m_dwBaseSaveSize > 0 && m_pbBaseSaveData != NULL; } +void LevelGenerationOptions::deleteBaseSaveData() { if(m_pbBaseSaveData) delete m_pbBaseSaveData; m_pbBaseSaveData = NULL; m_dwBaseSaveSize = 0; } + +bool LevelGenerationOptions::hasLoadedData() { return m_hasLoadedData; } +void LevelGenerationOptions::setLoadedData() { m_hasLoadedData = true; } + +__int64 LevelGenerationOptions::getLevelSeed() { return m_seed; } +Pos *LevelGenerationOptions::getSpawnPos() { return m_spawnPos; } +bool LevelGenerationOptions::getuseFlatWorld() { return m_useFlatWorld; } + +bool LevelGenerationOptions::requiresGameRules() { return m_bRequiresGameRules; } +void LevelGenerationOptions::setRequiredGameRules(LevelRuleset *rules) { m_requiredGameRules = rules; m_bRequiresGameRules = true; } +LevelRuleset *LevelGenerationOptions::getRequiredGameRules() { return m_requiredGameRules; } \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerationOptions.h b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.h new file mode 100644 index 0000000..0cc9da7 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerationOptions.h @@ -0,0 +1,216 @@ +#pragma once +using namespace std; + +#pragma message("LevelGenerationOptions.h ") + +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\StructureFeature.h" + +class ApplySchematicRuleDefinition; +class LevelChunk; +class ConsoleGenerateStructure; +class ConsoleSchematicFile; +class LevelRuleset; +class BiomeOverride; +class StartFeature; + +class GrSource +{ +public: + // 4J-JEV: + // Moved all this here; I didn't like that all this header information + // was being mixed in with all the game information as they have + // completely different lifespans. + + virtual bool requiresTexturePack()=0; + virtual UINT getRequiredTexturePackId()=0; + virtual wstring getDefaultSaveName()=0; + virtual LPCWSTR getWorldName()=0; + virtual LPCWSTR getDisplayName()=0; + virtual wstring getGrfPath()=0; + virtual bool requiresBaseSave() = 0; + virtual wstring getBaseSavePath() = 0; + + virtual void setRequiresTexturePack(bool)=0; + virtual void setRequiredTexturePackId(UINT)=0; + virtual void setDefaultSaveName(const wstring &)=0; + virtual void setWorldName(const wstring &)=0; + virtual void setDisplayName(const wstring &)=0; + virtual void setGrfPath(const wstring &)=0; + virtual void setBaseSavePath(const wstring &)=0; + + virtual bool ready()=0; + + //virtual void getGrfData(PBYTE &pData, DWORD &pSize)=0; +}; + +class JustGrSource : public GrSource +{ +protected: + wstring m_worldName; + wstring m_displayName; + wstring m_defaultSaveName; + bool m_bRequiresTexturePack; + int m_requiredTexturePackId; + wstring m_grfPath; + wstring m_baseSavePath; + bool m_bRequiresBaseSave; + +public: + virtual bool requiresTexturePack(); + virtual UINT getRequiredTexturePackId(); + virtual wstring getDefaultSaveName(); + virtual LPCWSTR getWorldName(); + virtual LPCWSTR getDisplayName(); + virtual wstring getGrfPath(); + virtual bool requiresBaseSave(); + virtual wstring getBaseSavePath(); + + virtual void setRequiresTexturePack(bool x); + virtual void setRequiredTexturePackId(UINT x); + virtual void setDefaultSaveName(const wstring &x); + virtual void setWorldName(const wstring &x); + virtual void setDisplayName(const wstring &x); + virtual void setGrfPath(const wstring &x); + virtual void setBaseSavePath(const wstring &x); + + virtual bool ready(); + + JustGrSource(); +}; + +class LevelGenerationOptions : public GameRuleDefinition +{ +public: + enum eSrc + { + eSrc_none, + + eSrc_fromSave, // Neither content or header is persistent. + + eSrc_fromDLC, // Header is persistent, content should be deleted to conserve space. + + eSrc_tutorial, // Both header and content is persistent, content cannot be reloaded. + + eSrc_MAX + }; + +private: + eSrc m_src; + + GrSource *m_pSrc; + GrSource *info(); + + bool m_hasLoadedData; + + PBYTE m_pbBaseSaveData; + DWORD m_dwBaseSaveSize; + +public: + + void setSrc(eSrc src); + eSrc getSrc(); + + bool isTutorial(); + bool isFromSave(); + bool isFromDLC(); + + bool requiresTexturePack(); + UINT getRequiredTexturePackId(); + wstring getDefaultSaveName(); + LPCWSTR getWorldName(); + LPCWSTR getDisplayName(); + wstring getGrfPath(); + bool requiresBaseSave(); + wstring getBaseSavePath(); + + void setGrSource(GrSource *grs); + + void setRequiresTexturePack(bool x); + void setRequiredTexturePackId(UINT x); + void setDefaultSaveName(const wstring &x); + void setWorldName(const wstring &x); + void setDisplayName(const wstring &x); + void setGrfPath(const wstring &x); + void setBaseSavePath(const wstring &x); + + bool ready(); + + void setBaseSaveData(PBYTE pbData, DWORD dwSize); + PBYTE getBaseSaveData(DWORD &size); + bool hasBaseSaveData(); + void deleteBaseSaveData(); + + bool hasLoadedData(); + void setLoadedData(); + +private: + // This should match the "MapOptionsRule" definition in the XML schema + __int64 m_seed; + bool m_useFlatWorld; + Pos *m_spawnPos; + vector m_schematicRules; + vector m_structureRules; + bool m_bHaveMinY; + int m_minY; + unordered_map m_schematics; + vector m_biomeOverrides; + vector m_features; + + bool m_bRequiresGameRules; + LevelRuleset *m_requiredGameRules; + + StringTable *m_stringTable; + +public: + LevelGenerationOptions(); + ~LevelGenerationOptions(); + + virtual ConsoleGameRules::EGameRuleType getActionType(); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void getChildren(vector *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + __int64 getLevelSeed(); + Pos *getSpawnPos(); + bool getuseFlatWorld(); + + void processSchematics(LevelChunk *chunk); + void processSchematicsLighting(LevelChunk *chunk); + + bool checkIntersects(int x0, int y0, int z0, int x1, int y1, int z1); + +private: + void clearSchematics(); + +public: + ConsoleSchematicFile *loadSchematicFile(const wstring &filename, PBYTE pbData, DWORD dwLen); + +public: + ConsoleSchematicFile *getSchematicFile(const wstring &filename); + void releaseSchematicFile(const wstring &filename); + + bool requiresGameRules(); + void setRequiredGameRules(LevelRuleset *rules); + LevelRuleset *getRequiredGameRules(); + + void getBiomeOverride(int biomeId, BYTE &tile, BYTE &topTile); + bool isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature); + + void loadStringTable(StringTable *table); + LPCWSTR getString(const wstring &key); + + unordered_map *getUnfinishedSchematicFiles(); + + // 4J-JEV: + // ApplySchematicRules contain limited state + // which needs to be reset BEFORE a new game starts. + void reset_start(); + + // 4J-JEV: + // This file contains state that needs to be deleted + // or reset once a game has finished. + void reset_finish(); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerators.cpp b/Minecraft.Client/Common/GameRules/LevelGenerators.cpp new file mode 100644 index 0000000..653a26d --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerators.cpp @@ -0,0 +1,26 @@ +#include "stdafx.h" +#include "LevelGenerationOptions.h" +#include "LevelGenerators.h" + + +LevelGenerators::LevelGenerators() +{ +} + +void LevelGenerators::addLevelGenerator(const wstring &displayName, LevelGenerationOptions *generator) +{ + if(!displayName.empty()) generator->setDisplayName(displayName); + m_levelGenerators.push_back(generator); +} + +void LevelGenerators::removeLevelGenerator(LevelGenerationOptions *generator) +{ + vector::iterator it; + while ( (it = find( m_levelGenerators.begin(), + m_levelGenerators.end(), + generator ) ) + != m_levelGenerators.end() ) + { + m_levelGenerators.erase(it); + } +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelGenerators.h b/Minecraft.Client/Common/GameRules/LevelGenerators.h new file mode 100644 index 0000000..824b838 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelGenerators.h @@ -0,0 +1,19 @@ +#pragma once + +using namespace std; + +class LevelGenerationOptions; + +class LevelGenerators +{ +private: + vector m_levelGenerators; + +public: + LevelGenerators(); + + void addLevelGenerator(const wstring &displayName, LevelGenerationOptions *generator); + void removeLevelGenerator(LevelGenerationOptions *generator); + + vector *getLevelGenerators() { return &m_levelGenerators; } +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelRules.cpp b/Minecraft.Client/Common/GameRules/LevelRules.cpp new file mode 100644 index 0000000..b7c8a8a --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRules.cpp @@ -0,0 +1,20 @@ +#include "stdafx.h" +#include "LevelRules.h" + + +LevelRules::LevelRules() +{ +} + +void LevelRules::addLevelRule(const wstring &displayName, PBYTE pbData, DWORD dwLen) +{ +} + +void LevelRules::addLevelRule(const wstring &displayName, LevelRuleset *rootRule) +{ +} + +void LevelRules::removeLevelRule(LevelRuleset *removing) +{ + // TODO ? +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelRules.h b/Minecraft.Client/Common/GameRules/LevelRules.h new file mode 100644 index 0000000..a94a212 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRules.h @@ -0,0 +1,14 @@ +#pragma once + +class LevelRuleset; + +class LevelRules +{ +public: + LevelRules(); + + void addLevelRule(const wstring &displayName, PBYTE pbData, DWORD dwLen); + void addLevelRule(const wstring &displayName, LevelRuleset *rootRule); + + void removeLevelRule(LevelRuleset *removing); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/LevelRuleset.cpp b/Minecraft.Client/Common/GameRules/LevelRuleset.cpp new file mode 100644 index 0000000..1c7ecd4 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRuleset.cpp @@ -0,0 +1,71 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\StringTable.h" +#include "ConsoleGameRules.h" +#include "LevelRuleset.h" + +LevelRuleset::LevelRuleset() +{ + m_stringTable = NULL; +} + +LevelRuleset::~LevelRuleset() +{ + for(AUTO_VAR(it, m_areas.begin()); it != m_areas.end(); ++it) + { + delete *it; + } +} + +void LevelRuleset::getChildren(vector *children) +{ + CompoundGameRuleDefinition::getChildren(children); + for (AUTO_VAR(it, m_areas.begin()); it != m_areas.end(); it++) + children->push_back(*it); +} + +GameRuleDefinition *LevelRuleset::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_NamedArea) + { + rule = new NamedAreaRuleDefinition(); + m_areas.push_back((NamedAreaRuleDefinition *)rule); + } + else + { + rule = CompoundGameRuleDefinition::addChild(ruleType); + } + return rule; +} + +void LevelRuleset::loadStringTable(StringTable *table) +{ + m_stringTable = table; +} + +LPCWSTR LevelRuleset::getString(const wstring &key) +{ + if(m_stringTable == NULL) + { + return L""; + } + else + { + return m_stringTable->getString(key); + } +} + +AABB *LevelRuleset::getNamedArea(const wstring &areaName) +{ + AABB *area = NULL; + for(AUTO_VAR(it, m_areas.begin()); it != m_areas.end(); ++it) + { + if( (*it)->getName().compare(areaName) == 0 ) + { + area = (*it)->getArea(); + break; + } + } + return area; +} diff --git a/Minecraft.Client/Common/GameRules/LevelRuleset.h b/Minecraft.Client/Common/GameRules/LevelRuleset.h new file mode 100644 index 0000000..bbb17c4 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/LevelRuleset.h @@ -0,0 +1,27 @@ +#pragma once + +#include "CompoundGameRuleDefinition.h" + +class NamedAreaRuleDefinition; + +class LevelRuleset : public CompoundGameRuleDefinition +{ +private: + vector m_areas; + StringTable *m_stringTable; +public: + LevelRuleset(); + ~LevelRuleset(); + + virtual void getChildren(vector *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_LevelRules; } + + void loadStringTable(StringTable *table); + LPCWSTR getString(const wstring &key); + + AABB *getNamedArea(const wstring &areaName); + + StringTable *getStringTable() { return m_stringTable; } +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp new file mode 100644 index 0000000..41ff15e --- /dev/null +++ b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.cpp @@ -0,0 +1,84 @@ +#include "stdafx.h" +#include "NamedAreaRuleDefinition.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.phys.h" + +NamedAreaRuleDefinition::NamedAreaRuleDefinition() +{ + m_name = L""; + m_area = AABB::newPermanent(0,0,0,0,0,0); +} + +NamedAreaRuleDefinition::~NamedAreaRuleDefinition() +{ + delete m_area; +} + +void NamedAreaRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 7); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_name); + dos->writeUTF(m_name); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x0); + dos->writeUTF(_toString(m_area->x0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y0); + dos->writeUTF(_toString(m_area->y0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z0); + dos->writeUTF(_toString(m_area->z0)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x1); + dos->writeUTF(_toString(m_area->x1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y1); + dos->writeUTF(_toString(m_area->y1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z1); + dos->writeUTF(_toString(m_area->z1)); +} + +void NamedAreaRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"name") == 0) + { + m_name = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"NamedAreaRuleDefinition: Adding parameter name=%ls\n",m_name.c_str()); +#endif + } + else if(attributeName.compare(L"x0") == 0) + { + m_area->x0 = _fromString(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter x0=%f\n",m_area->x0); + } + else if(attributeName.compare(L"y0") == 0) + { + m_area->y0 = _fromString(attributeValue); + if(m_area->y0 < 0) m_area->y0 = 0; + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter y0=%f\n",m_area->y0); + } + else if(attributeName.compare(L"z0") == 0) + { + m_area->z0 = _fromString(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter z0=%f\n",m_area->z0); + } + else if(attributeName.compare(L"x1") == 0) + { + m_area->x1 = _fromString(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter x1=%f\n",m_area->x1); + } + else if(attributeName.compare(L"y1") == 0) + { + m_area->y1 = _fromString(attributeValue); + if(m_area->y1 < 0) m_area->y1 = 0; + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter y1=%f\n",m_area->y1); + } + else if(attributeName.compare(L"z1") == 0) + { + m_area->z1 = _fromString(attributeValue); + app.DebugPrintf("NamedAreaRuleDefinition: Adding parameter z1=%f\n",m_area->z1); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} diff --git a/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h new file mode 100644 index 0000000..7cf7db1 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/NamedAreaRuleDefinition.h @@ -0,0 +1,23 @@ +#pragma once + +#include "GameRuleDefinition.h" + +class NamedAreaRuleDefinition : public GameRuleDefinition +{ +private: + wstring m_name; + AABB *m_area; + +public: + NamedAreaRuleDefinition(); + ~NamedAreaRuleDefinition(); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_NamedArea; } + + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + AABB *getArea() { return m_area; } + wstring getName() { return m_name; } +}; diff --git a/Minecraft.Client/Common/GameRules/StartFeature.cpp b/Minecraft.Client/Common/GameRules/StartFeature.cpp new file mode 100644 index 0000000..9d5f15c --- /dev/null +++ b/Minecraft.Client/Common/GameRules/StartFeature.cpp @@ -0,0 +1,53 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "StartFeature.h" + +StartFeature::StartFeature() +{ + m_chunkX = 0; + m_chunkZ = 0; + m_feature = StructureFeature::eFeature_Temples; +} + +void StartFeature::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + GameRuleDefinition::writeAttributes(dos, numAttrs + 3); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_chunkX); + dos->writeUTF(_toString(m_chunkX)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_chunkZ); + dos->writeUTF(_toString(m_chunkZ)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_feature); + dos->writeUTF(_toString((int)m_feature)); +} + +void StartFeature::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"chunkX") == 0) + { + int value = _fromString(attributeValue); + m_chunkX = value; + app.DebugPrintf("StartFeature: Adding parameter chunkX=%d\n",m_chunkX); + } + else if(attributeName.compare(L"chunkZ") == 0) + { + int value = _fromString(attributeValue); + m_chunkZ = value; + app.DebugPrintf("StartFeature: Adding parameter chunkZ=%d\n",m_chunkZ); + } + else if(attributeName.compare(L"feature") == 0) + { + int value = _fromString(attributeValue); + m_feature = (StructureFeature::EFeatureTypes)value; + app.DebugPrintf("StartFeature: Adding parameter feature=%d\n",m_feature); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool StartFeature::isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature) +{ + return chunkX == m_chunkX && chunkZ == m_chunkZ && feature == m_feature; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/StartFeature.h b/Minecraft.Client/Common/GameRules/StartFeature.h new file mode 100644 index 0000000..d3f1280 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/StartFeature.h @@ -0,0 +1,22 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\StructureFeature.h" + +class StartFeature : public GameRuleDefinition +{ +private: + int m_chunkX, m_chunkZ; + StructureFeature::EFeatureTypes m_feature; + +public: + StartFeature(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_StartFeature; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool isFeatureChunk(int chunkX, int chunkZ, StructureFeature::EFeatureTypes feature); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp new file mode 100644 index 0000000..6e55cd4 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.cpp @@ -0,0 +1,171 @@ +#include "stdafx.h" +#include "UpdatePlayerRuleDefinition.h" +#include "ConsoleGameRules.h" +#include "..\..\..\Minecraft.World\Pos.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.entity.player.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.food.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.item.h" + +UpdatePlayerRuleDefinition::UpdatePlayerRuleDefinition() +{ + m_bUpdateHealth = m_bUpdateFood = m_bUpdateYRot = false;; + m_health = 0; + m_food = 0; + m_spawnPos = NULL; + m_yRot = 0.0f; +} + +UpdatePlayerRuleDefinition::~UpdatePlayerRuleDefinition() +{ + for(AUTO_VAR(it, m_items.begin()); it != m_items.end(); ++it) + { + delete *it; + } +} + +void UpdatePlayerRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + int attrCount = 3; + if(m_bUpdateHealth) ++attrCount; + if(m_bUpdateFood) ++attrCount; + if(m_bUpdateYRot) ++attrCount; + GameRuleDefinition::writeAttributes(dos, numAttributes + attrCount ); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnX); + dos->writeUTF(_toString(m_spawnPos->x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnY); + dos->writeUTF(_toString(m_spawnPos->y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_spawnZ); + dos->writeUTF(_toString(m_spawnPos->z)); + + if(m_bUpdateYRot) + { + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_yRot); + dos->writeUTF(_toString(m_yRot)); + } + if(m_bUpdateHealth) + { + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_food); + dos->writeUTF(_toString(m_health)); + } + if(m_bUpdateFood) + { + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_health); + dos->writeUTF(_toString(m_food)); + } +} + +void UpdatePlayerRuleDefinition::getChildren(vector *children) +{ + GameRuleDefinition::getChildren(children); + for(AUTO_VAR(it, m_items.begin()); it!=m_items.end(); it++) + children->push_back(*it); +} + +GameRuleDefinition *UpdatePlayerRuleDefinition::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_AddItem) + { + rule = new AddItemRuleDefinition(); + m_items.push_back((AddItemRuleDefinition *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"UpdatePlayerRuleDefinition: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void UpdatePlayerRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"spawnX") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString(attributeValue); + m_spawnPos->x = value; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter spawnX=%d\n",value); + } + else if(attributeName.compare(L"spawnY") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString(attributeValue); + m_spawnPos->y = value; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter spawnY=%d\n",value); + } + else if(attributeName.compare(L"spawnZ") == 0) + { + if(m_spawnPos == NULL) m_spawnPos = new Pos(); + int value = _fromString(attributeValue); + m_spawnPos->z = value; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter spawnZ=%d\n",value); + } + else if(attributeName.compare(L"health") == 0) + { + int value = _fromString(attributeValue); + m_health = value; + m_bUpdateHealth = true; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter health=%d\n",value); + } + else if(attributeName.compare(L"food") == 0) + { + int value = _fromString(attributeValue); + m_food = value; + m_bUpdateFood = true; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter health=%d\n",value); + } + else if(attributeName.compare(L"yRot") == 0) + { + float value = _fromString(attributeValue); + m_yRot = value; + m_bUpdateYRot = true; + app.DebugPrintf("UpdatePlayerRuleDefinition: Adding parameter yRot=%f\n",value); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +void UpdatePlayerRuleDefinition::postProcessPlayer(shared_ptr player) +{ + if(m_bUpdateHealth) + { + player->lastHealth = m_health; + player->setHealth(m_health); + } + + if(m_bUpdateFood) + { + player->getFoodData()->setFoodLevel(m_food); + } + + double x = player->x; + double y = player->y; + double z = player->z; + float yRot = player->yRot; + float xRot = player->xRot; + if(m_spawnPos != NULL) + { + x = m_spawnPos->x; + y = m_spawnPos->y; + z = m_spawnPos->z; + } + + if(m_bUpdateYRot) + { + yRot = m_yRot; + } + + if(m_spawnPos != NULL || m_bUpdateYRot) player->absMoveTo(x,y,z,yRot,xRot); + + for(AUTO_VAR(it, m_items.begin()); it != m_items.end(); ++it) + { + AddItemRuleDefinition *addItem = *it; + + addItem->addItemToContainer(player->inventory, -1); + } +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h new file mode 100644 index 0000000..538aefa --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UpdatePlayerRuleDefinition.h @@ -0,0 +1,33 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" + +class AddItemRuleDefinition; +class Pos; + +class UpdatePlayerRuleDefinition : public GameRuleDefinition +{ +private: + vector m_items; + + bool m_bUpdateHealth, m_bUpdateFood, m_bUpdateYRot, m_bUpdateInventory; + int m_health; + int m_food; + Pos *m_spawnPos; + float m_yRot; + +public: + UpdatePlayerRuleDefinition(); + ~UpdatePlayerRuleDefinition(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_UpdatePlayerRule; } + + virtual void getChildren(vector *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual void postProcessPlayer(shared_ptr player); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp new file mode 100644 index 0000000..965405a --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.cpp @@ -0,0 +1,82 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "UseTileRuleDefinition.h" + +UseTileRuleDefinition::UseTileRuleDefinition() +{ + m_tileId = -1; + m_useCoords = false; +} + +void UseTileRuleDefinition::writeAttributes(DataOutputStream *dos, UINT numAttributes) +{ + GameRuleDefinition::writeAttributes(dos, numAttributes + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_tileId); + dos->writeUTF(_toString(m_tileId)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_useCoords); + dos->writeUTF(_toString(m_useCoords)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_coordinates.x)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_coordinates.y)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_coordinates.z)); +} + +void UseTileRuleDefinition::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"tileId") == 0) + { + m_tileId = _fromString(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter tileId=%d\n",m_tileId); + } + else if(attributeName.compare(L"useCoords") == 0) + { + m_useCoords = _fromString(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter useCoords=%s\n",m_useCoords?"TRUE":"FALSE"); + } + else if(attributeName.compare(L"x") == 0) + { + m_coordinates.x = _fromString(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter x=%d\n",m_coordinates.x); + } + else if(attributeName.compare(L"y") == 0) + { + m_coordinates.y = _fromString(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter y=%d\n",m_coordinates.y); + } + else if(attributeName.compare(L"z") == 0) + { + m_coordinates.z = _fromString(attributeValue); + app.DebugPrintf("UseTileRule: Adding parameter z=%d\n",m_coordinates.z); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool UseTileRuleDefinition::onUseTile(GameRule *rule, int tileId, int x, int y, int z) +{ + bool statusChanged = false; + if( m_tileId == tileId ) + { + if( !m_useCoords || (m_coordinates.x == x && m_coordinates.y == y && m_coordinates.z == z) ) + { + if(!getComplete(rule)) + { + statusChanged = true; + setComplete(rule,true); + app.DebugPrintf("Completed UseTileRule with info - t:%d, coords:%s, x:%d, y:%d, z:%d\n", m_tileId,m_useCoords?"TRUE":"FALSE",m_coordinates.x,m_coordinates.y,m_coordinates.z); + + // Send a packet or some other announcement here + } + } + } + return statusChanged; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h new file mode 100644 index 0000000..ad64bfe --- /dev/null +++ b/Minecraft.Client/Common/GameRules/UseTileRuleDefinition.h @@ -0,0 +1,24 @@ +#pragma once +using namespace std; + +#include "GameRuleDefinition.h" +#include "..\..\..\Minecraft.World\Pos.h" + +class UseTileRuleDefinition : public GameRuleDefinition +{ +private: + // These values should map directly to the xsd definition for this Rule + int m_tileId; + bool m_useCoords; + Pos m_coordinates; + +public: + UseTileRuleDefinition(); + + ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_UseTileRule; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + virtual bool onUseTile(GameRule *rule, int tileId, int x, int y, int z); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp new file mode 100644 index 0000000..6d687b3 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.cpp @@ -0,0 +1,104 @@ +#include "stdafx.h" +#include "XboxStructureActionGenerateBox.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" + +XboxStructureActionGenerateBox::XboxStructureActionGenerateBox() +{ + m_x0 = m_y0 = m_z0 = m_x1 = m_y1 = m_z1 = m_edgeTile = m_fillTile = 0; + m_skipAir = false; +} + +void XboxStructureActionGenerateBox::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + ConsoleGenerateStructureAction::writeAttributes(dos, numAttrs + 9); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x0); + dos->writeUTF(_toString(m_x0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y0); + dos->writeUTF(_toString(m_y0)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z0); + dos->writeUTF(_toString(m_z0)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x1); + dos->writeUTF(_toString(m_x1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y1); + dos->writeUTF(_toString(m_y1)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z1); + dos->writeUTF(_toString(m_z1)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_edgeTile); + dos->writeUTF(_toString(m_edgeTile)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_fillTile); + dos->writeUTF(_toString(m_fillTile)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_skipAir); + dos->writeUTF(_toString(m_skipAir)); +} + +void XboxStructureActionGenerateBox::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"x0") == 0) + { + int value = _fromString(attributeValue); + m_x0 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter x0=%d\n",m_x0); + } + else if(attributeName.compare(L"y0") == 0) + { + int value = _fromString(attributeValue); + m_y0 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter y0=%d\n",m_y0); + } + else if(attributeName.compare(L"z0") == 0) + { + int value = _fromString(attributeValue); + m_z0 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter z0=%d\n",m_z0); + } + else if(attributeName.compare(L"x1") == 0) + { + int value = _fromString(attributeValue); + m_x1 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter x1=%d\n",m_x1); + } + else if(attributeName.compare(L"y1") == 0) + { + int value = _fromString(attributeValue); + m_y1 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter y1=%d\n",m_y1); + } + else if(attributeName.compare(L"z1") == 0) + { + int value = _fromString(attributeValue); + m_z1 = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter z1=%d\n",m_z1); + } + else if(attributeName.compare(L"edgeTile") == 0) + { + int value = _fromString(attributeValue); + m_edgeTile = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter edgeTile=%d\n",m_edgeTile); + } + else if(attributeName.compare(L"fillTile") == 0) + { + int value = _fromString(attributeValue); + m_fillTile = value; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter fillTile=%d\n",m_fillTile); + } + else if(attributeName.compare(L"skipAir") == 0) + { + if(attributeValue.compare(L"true") == 0) m_skipAir = true; + app.DebugPrintf("XboxStructureActionGenerateBox: Adding parameter skipAir=%s\n",m_skipAir?"TRUE":"FALSE"); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionGenerateBox::generateBoxInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + app.DebugPrintf("XboxStructureActionGenerateBox - generating a box\n"); + structure->generateBox(level,chunkBB,m_x0,m_y0,m_z0,m_x1,m_y1,m_z1,m_edgeTile,m_fillTile,m_skipAir); + return true; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h new file mode 100644 index 0000000..78664d4 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionGenerateBox.h @@ -0,0 +1,26 @@ +#pragma once +#include "ConsoleGenerateStructureAction.h" + +class StructurePiece; +class Level; +class BoundingBox; + +class XboxStructureActionGenerateBox : public ConsoleGenerateStructureAction +{ +private: + int m_x0, m_y0, m_z0, m_x1, m_y1, m_z1, m_edgeTile, m_fillTile; + bool m_skipAir; +public: + XboxStructureActionGenerateBox(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_GenerateBox; } + + virtual int getEndX() { return m_x1; } + virtual int getEndY() { return m_y1; } + virtual int getEndZ() { return m_z1; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool generateBoxInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp new file mode 100644 index 0000000..b816d5b --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.cpp @@ -0,0 +1,72 @@ +#include "stdafx.h" +#include "XboxStructureActionPlaceBlock.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" + +XboxStructureActionPlaceBlock::XboxStructureActionPlaceBlock() +{ + m_x = m_y = m_z = m_tile = m_data = 0; +} + +void XboxStructureActionPlaceBlock::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + ConsoleGenerateStructureAction::writeAttributes(dos, numAttrs + 5); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_x); + dos->writeUTF(_toString(m_x)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_y); + dos->writeUTF(_toString(m_y)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_z); + dos->writeUTF(_toString(m_z)); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_data); + dos->writeUTF(_toString(m_data)); + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_block); + dos->writeUTF(_toString(m_tile)); +} + + +void XboxStructureActionPlaceBlock::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"x") == 0) + { + int value = _fromString(attributeValue); + m_x = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter x=%d\n",m_x); + } + else if(attributeName.compare(L"y") == 0) + { + int value = _fromString(attributeValue); + m_y = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter y=%d\n",m_y); + } + else if(attributeName.compare(L"z") == 0) + { + int value = _fromString(attributeValue); + m_z = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter z=%d\n",m_z); + } + else if(attributeName.compare(L"block") == 0) + { + int value = _fromString(attributeValue); + m_tile = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter block=%d\n",m_tile); + } + else if(attributeName.compare(L"data") == 0) + { + int value = _fromString(attributeValue); + m_data = value; + app.DebugPrintf("XboxStructureActionPlaceBlock: Adding parameter data=%d\n",m_data); + } + else + { + GameRuleDefinition::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionPlaceBlock::placeBlockInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + app.DebugPrintf("XboxStructureActionPlaceBlock - placing a block\n"); + structure->placeBlock(level,m_tile,m_data,m_x,m_y,m_z,chunkBB); + return true; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h new file mode 100644 index 0000000..3ee377b --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceBlock.h @@ -0,0 +1,25 @@ +#pragma once +#include "ConsoleGenerateStructureAction.h" + +class StructurePiece; +class Level; +class BoundingBox; + +class XboxStructureActionPlaceBlock : public ConsoleGenerateStructureAction +{ +protected: + int m_x, m_y, m_z, m_tile, m_data; +public: + XboxStructureActionPlaceBlock(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_PlaceBlock; } + + virtual int getEndX() { return m_x; } + virtual int getEndY() { return m_y; } + virtual int getEndZ() { return m_z; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool placeBlockInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp new file mode 100644 index 0000000..8184f45 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.cpp @@ -0,0 +1,99 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XboxStructureActionPlaceContainer.h" +#include "AddItemRuleDefinition.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h" + +XboxStructureActionPlaceContainer::XboxStructureActionPlaceContainer() +{ + m_tile = Tile::chest_Id; +} + +XboxStructureActionPlaceContainer::~XboxStructureActionPlaceContainer() +{ + for(AUTO_VAR(it, m_items.begin()); it != m_items.end(); ++it) + { + delete *it; + } +} + +// 4J-JEV: Super class handles attr-facing fine. +//void XboxStructureActionPlaceContainer::writeAttributes(DataOutputStream *dos, UINT numAttrs) + + +void XboxStructureActionPlaceContainer::getChildren(vector *children) +{ + XboxStructureActionPlaceBlock::getChildren(children); + for(AUTO_VAR(it, m_items.begin()); it!=m_items.end(); it++) + children->push_back( *it ); +} + +GameRuleDefinition *XboxStructureActionPlaceContainer::addChild(ConsoleGameRules::EGameRuleType ruleType) +{ + GameRuleDefinition *rule = NULL; + if(ruleType == ConsoleGameRules::eGameRuleType_AddItem) + { + rule = new AddItemRuleDefinition(); + m_items.push_back((AddItemRuleDefinition *)rule); + } + else + { +#ifndef _CONTENT_PACKAGE + wprintf(L"XboxStructureActionPlaceContainer: Attempted to add invalid child rule - %d\n", ruleType ); +#endif + } + return rule; +} + +void XboxStructureActionPlaceContainer::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"facing") == 0) + { + int value = _fromString(attributeValue); + m_data = value; + app.DebugPrintf("XboxStructureActionPlaceContainer: Adding parameter facing=%d\n",m_data); + } + else + { + XboxStructureActionPlaceBlock::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionPlaceContainer::placeContainerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + int worldX = structure->getWorldX( m_x, m_z ); + int worldY = structure->getWorldY( m_y ); + int worldZ = structure->getWorldZ( m_x, m_z ); + + if ( chunkBB->isInside( worldX, worldY, worldZ ) ) + { + if ( level->getTileEntity( worldX, worldY, worldZ ) != NULL ) + { + // Remove the current tile entity + level->removeTileEntity( worldX, worldY, worldZ ); + level->setTile( worldX, worldY, worldZ, 0 ); + } + + level->setTile( worldX, worldY, worldZ, m_tile ); + shared_ptr container = dynamic_pointer_cast(level->getTileEntity( worldX, worldY, worldZ )); + + app.DebugPrintf("XboxStructureActionPlaceContainer - placing a container at (%d,%d,%d)\n", worldX, worldY, worldZ); + if ( container != NULL ) + { + level->setData( worldX, worldY, worldZ, m_data); + // Add items + int slotId = 0; + for(AUTO_VAR(it, m_items.begin()); it != m_items.end() && (slotId < container->getContainerSize()); ++it, ++slotId ) + { + AddItemRuleDefinition *addItem = *it; + + addItem->addItemToContainer(container,slotId); + } + } + return true; + } + return false; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h new file mode 100644 index 0000000..6355ca1 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceContainer.h @@ -0,0 +1,29 @@ +#pragma once + +#include "XboxStructureActionPlaceBlock.h" + +class AddItemRuleDefinition; +class StructurePiece; +class Level; +class BoundingBox; + +class XboxStructureActionPlaceContainer : public XboxStructureActionPlaceBlock +{ +private: + vector m_items; +public: + XboxStructureActionPlaceContainer(); + ~XboxStructureActionPlaceContainer(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_PlaceContainer; } + + virtual void getChildren(vector *children); + virtual GameRuleDefinition *addChild(ConsoleGameRules::EGameRuleType ruleType); + + // 4J-JEV: Super class handles attr-facing fine. + //virtual void writeAttributes(DataOutputStream *dos, UINT numAttributes); + + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool placeContainerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp new file mode 100644 index 0000000..1eca334 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.cpp @@ -0,0 +1,69 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "XboxStructureActionPlaceSpawner.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.levelgen.structure.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.entity.h" + +XboxStructureActionPlaceSpawner::XboxStructureActionPlaceSpawner() +{ + m_tile = Tile::mobSpawner_Id; + m_entityId = L"Pig"; +} + +XboxStructureActionPlaceSpawner::~XboxStructureActionPlaceSpawner() +{ +} + +void XboxStructureActionPlaceSpawner::writeAttributes(DataOutputStream *dos, UINT numAttrs) +{ + XboxStructureActionPlaceBlock::writeAttributes(dos, numAttrs + 1); + + ConsoleGameRules::write(dos, ConsoleGameRules::eGameRuleAttr_entity); + dos->writeUTF(m_entityId); +} + +void XboxStructureActionPlaceSpawner::addAttribute(const wstring &attributeName, const wstring &attributeValue) +{ + if(attributeName.compare(L"entity") == 0) + { + m_entityId = attributeValue; +#ifndef _CONTENT_PACKAGE + wprintf(L"XboxStructureActionPlaceSpawner: Adding parameter entity=%ls\n",m_entityId.c_str()); +#endif + } + else + { + XboxStructureActionPlaceBlock::addAttribute(attributeName, attributeValue); + } +} + +bool XboxStructureActionPlaceSpawner::placeSpawnerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB) +{ + int worldX = structure->getWorldX( m_x, m_z ); + int worldY = structure->getWorldY( m_y ); + int worldZ = structure->getWorldZ( m_x, m_z ); + + if ( chunkBB->isInside( worldX, worldY, worldZ ) ) + { + if ( level->getTileEntity( worldX, worldY, worldZ ) != NULL ) + { + // Remove the current tile entity + level->removeTileEntity( worldX, worldY, worldZ ); + level->setTile( worldX, worldY, worldZ, 0 ); + } + + level->setTile( worldX, worldY, worldZ, m_tile ); + shared_ptr entity = dynamic_pointer_cast(level->getTileEntity( worldX, worldY, worldZ )); + +#ifndef _CONTENT_PACKAGE + wprintf(L"XboxStructureActionPlaceSpawner - placing a %ls spawner at (%d,%d,%d)\n", m_entityId.c_str(), worldX, worldY, worldZ); +#endif + if( entity != NULL ) + { + entity->setEntityId(m_entityId); + } + return true; + } + return false; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h new file mode 100644 index 0000000..1600098 --- /dev/null +++ b/Minecraft.Client/Common/GameRules/XboxStructureActionPlaceSpawner.h @@ -0,0 +1,24 @@ +#pragma once + +#include "XboxStructureActionPlaceBlock.h" + +class StructurePiece; +class Level; +class BoundingBox; +class GRFObject; + +class XboxStructureActionPlaceSpawner : public XboxStructureActionPlaceBlock +{ +private: + wstring m_entityId; +public: + XboxStructureActionPlaceSpawner(); + ~XboxStructureActionPlaceSpawner(); + + virtual ConsoleGameRules::EGameRuleType getActionType() { return ConsoleGameRules::eGameRuleType_PlaceSpawner; } + + virtual void writeAttributes(DataOutputStream *dos, UINT numAttrs); + virtual void addAttribute(const wstring &attributeName, const wstring &attributeValue); + + bool placeSpawnerInLevel(StructurePiece *structure, Level *level, BoundingBox *chunkBB); +}; \ No newline at end of file diff --git a/Minecraft.Client/Common/Leaderboards/LeaderboardManager.cpp b/Minecraft.Client/Common/Leaderboards/LeaderboardManager.cpp new file mode 100644 index 0000000..33707b1 --- /dev/null +++ b/Minecraft.Client/Common/Leaderboards/LeaderboardManager.cpp @@ -0,0 +1,106 @@ +#include "stdafx.h" + +#include "..\..\..\Minecraft.World\StringHelpers.h" + +#include "LeaderboardManager.h" + +const wstring LeaderboardManager::filterNames[eNumFilterModes] = + { + L"Friends", L"MyScore", L"TopRank" + }; + +void LeaderboardManager::DeleteInstance() +{ + delete m_instance; + m_instance = NULL; +} + +LeaderboardManager::LeaderboardManager() +{ + zeroReadParameters(); + + m_myXUID = INVALID_XUID; +} + +void LeaderboardManager::zeroReadParameters() +{ + m_difficulty = -1; + m_statsType = eStatsType_UNDEFINED; + m_readListener = NULL; + m_startIndex = 0; + m_readCount = 0; + m_eFilterMode = eFM_UNDEFINED; +} + +bool LeaderboardManager::ReadStats_Friends(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int startIndex, unsigned int readCount) +{ + zeroReadParameters(); + + m_readListener = listener; + m_difficulty = difficulty; + m_statsType = type; + + m_eFilterMode = eFM_Friends; + return true; +} + +bool LeaderboardManager::ReadStats_MyScore(LeaderboardReadListener *listener, int difficulty, EStatsType type, PlayerUID myUID, unsigned int readCount) +{ + zeroReadParameters(); + + m_readListener = listener; + m_difficulty = difficulty; + m_statsType = type; + + m_readCount = readCount; + + m_eFilterMode = eFM_MyScore; + return true; +} + +bool LeaderboardManager::ReadStats_TopRank(LeaderboardReadListener *listener, int difficulty, EStatsType type, unsigned int startIndex, unsigned int readCount) +{ + zeroReadParameters(); + + m_readListener = listener; + m_difficulty = difficulty; + m_statsType = type; + + m_startIndex = startIndex; + m_readCount = readCount; + + m_eFilterMode = eFM_TopRank; + return true; +} + +#ifndef _XBOX +void LeaderboardManager::printStats(ReadView &view) +{ + app.DebugPrintf("[LeaderboardManager] Printing stats:\n" + "\tnumQueries=%i\n", view.m_numQueries); + + for (int i=0; i>29)&0x7) +#define GET_SLOTDISPLAY_ALPHA_FROM_DATA_BITMASK(uiBitmask) ((((unsigned int)uiBitmask)>>24)&0x1F) +#define GET_SLOTDISPLAY_DECORATIONS_FROM_DATA_BITMASK(uiBitmask) ((((unsigned int)uiBitmask)&0x800000)?true:false) +//#define GET_SLOTDISPLAY_AUXVAL_FROM_DATA_BITMASK(uiBitmask) ((((unsigned long)uiBitmask)>>12)&0x7FF) +#define GET_SLOTDISPLAY_COUNT_FROM_DATA_BITMASK(uiBitmask) (((((unsigned int)uiBitmask)>>6)&0x3F)+1) +#define GET_SLOTDISPLAY_SCALE_FROM_DATA_BITMASK(uiBitmask) (((unsigned int)uiBitmask)&0x3F) +#define GET_SLOTDISPLAY_POPTIME_FROM_DATA_BITMASK(uiBitmask) ((((unsigned int)uiBitmask)>>20)&0x7) + +// 16 bits for id (either item id or xzp icon id) +// 15 bits for aux value +// 1 bit for foil +#define MAKE_SLOTDISPLAY_ITEM_BITMASK(uiId,uiAuxValue,bFoil) ( (uiId & 0xFFFF) | ((uiAuxValue & 0x7FFF) << 16) | (bFoil?0x80000000:0) ) + +#define GET_SLOTDISPLAY_ID_FROM_ITEM_BITMASK(uiBitmask) (((unsigned int)uiBitmask)&0xFFFF) +#define GET_SLOTDISPLAY_AUXVAL_FROM_ITEM_BITMASK(uiBitmask) ((((unsigned int)uiBitmask)>>16) & 0x7FFF) +#define GET_SLOTDISPLAY_FOIL_FROM_ITEM_BITMASK(uiBitmask) ((((unsigned int)uiBitmask)&0x80000000)?true:false) + + +// For encoding the players skin selection in their profile +// bDlcSkin = false is a players skin, bDlcSkin = true is a DLC skin +#define MAKE_SKIN_BITMASK(bDlcSkin, dwSkinId) ( (bDlcSkin?0x80000000:0) | (dwSkinId & 0x7FFFFFFF) ) +#define IS_SKIN_ID_IN_RANGE(dwSkinId) (dwSkinId <= 0x7FFFFFFF) + +#define GET_DLC_SKIN_ID_FROM_BITMASK(uiBitmask) (((DWORD)uiBitmask)&0x7FFFFFFF) +#define GET_UGC_SKIN_ID_FROM_BITMASK(uiBitmask) (((DWORD)uiBitmask)&0x7FFFFFE0) +#define GET_DEFAULT_SKIN_ID_FROM_BITMASK(uiBitmask) (((DWORD)uiBitmask)&0x0000001F) +#define GET_IS_DLC_SKIN_FROM_BITMASK(uiBitmask) ((((DWORD)uiBitmask)&0x80000000)?true:false) + diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.cpp b/Minecraft.Client/Common/Network/GameNetworkManager.cpp new file mode 100644 index 0000000..5110ae9 --- /dev/null +++ b/Minecraft.Client/Common/Network/GameNetworkManager.cpp @@ -0,0 +1,2006 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "..\..\..\Minecraft.World\AABB.h" +#include "..\..\..\Minecraft.World\Vec3.h" +#include "..\..\..\Minecraft.World\Socket.h" +#include "..\..\..\Minecraft.World\ThreadName.h" +#include "..\..\..\Minecraft.World\Entity.h" +#include "..\..\..\Minecraft.World\net.minecraft.world.level.tile.h" +#include "..\..\ClientConnection.h" +#include "..\..\Minecraft.h" +#include "..\..\User.h" +#include "..\..\MinecraftServer.h" +#include "..\..\PlayerList.h" +#include "..\..\ServerPlayer.h" +#include "..\..\PlayerConnection.h" +#include "..\..\MultiPlayerLevel.h" +#include "..\..\ProgressRenderer.h" +#include "..\..\MultiPlayerLocalPlayer.h" +#include "..\..\..\Minecraft.World\DisconnectPacket.h" +#include "..\..\..\Minecraft.World\compression.h" +#include "..\..\..\Minecraft.World\OldChunkStorage.h" +#include "..\..\TexturePackRepository.h" +#include "..\..\TexturePack.h" + +#include "..\..\Gui.h" +#include "..\..\LevelRenderer.h" +#include "..\..\..\Minecraft.World\IntCache.h" +#include "..\GameRules\ConsoleGameRules.h" +#include "GameNetworkManager.h" + +#ifdef _XBOX +#include "Common\XUI\XUI_PauseMenu.h" +#elif !(defined __PSVITA__) +#include "Common\UI\UI.h" +#include "Common\UI\UIScene_PauseMenu.h" +#include "..\..\Xbox\Network\NetworkPlayerXbox.h" +#endif + +#ifdef _DURANGO +#include "..\Minecraft.World\DurangoStats.h" +#endif + +// Global instance +CGameNetworkManager g_NetworkManager; +CPlatformNetworkManager *CGameNetworkManager::s_pPlatformNetworkManager; + +__int64 CGameNetworkManager::messageQueue[512]; +__int64 CGameNetworkManager::byteQueue[512]; +int CGameNetworkManager::messageQueuePos = 0; + +CGameNetworkManager::CGameNetworkManager() +{ + m_bInitialised = false; + m_bLastDisconnectWasLostRoomOnly = false; + m_bFullSessionMessageOnNextSessionChange = false; + +#ifdef __ORBIS__ + m_pUpsell = NULL; + m_pInviteInfo = NULL; +#endif +} + +void CGameNetworkManager::Initialise() +{ + ServerStoppedCreate( false ); + ServerReadyCreate( false ); + int flagIndexSize = LevelRenderer::getGlobalChunkCount() / (Level::maxBuildHeight / 16); // dividing here by number of renderer chunks in one column +#ifdef _XBOX + s_pPlatformNetworkManager = new CPlatformNetworkManagerXbox(); +#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ + s_pPlatformNetworkManager = new CPlatformNetworkManagerSony(); +#elif defined _DURANGO + s_pPlatformNetworkManager = new CPlatformNetworkManagerDurango(); +#else + s_pPlatformNetworkManager = new CPlatformNetworkManagerStub(); +#endif + s_pPlatformNetworkManager->Initialise( this, flagIndexSize ); + m_bNetworkThreadRunning = false; + m_bInitialised = true; +} + +void CGameNetworkManager::Terminate() +{ + if( m_bInitialised ) + { + s_pPlatformNetworkManager->Terminate(); + } +} + +void CGameNetworkManager::DoWork() +{ +#ifdef _XBOX + // did we get any notifications from the game listener? + if(app.GetNotifications()->size()!=0) + { + PNOTIFICATION pNotification=app.GetNotifications()->back(); + + switch(pNotification->dwNotification) + { + case XN_LIVE_LINK_STATE_CHANGED: + { + int iPrimaryPlayer = g_NetworkManager.GetPrimaryPad(); + bool bConnected = (pNotification->uiParam!=0)?true:false; + if((g_NetworkManager.GetLockedProfile()!=-1) && iPrimaryPlayer!=-1 && bConnected == false && g_NetworkManager.IsInSession() ) + { + app.SetAction(iPrimaryPlayer,eAppAction_EthernetDisconnected); + } + } + break; + case XN_LIVE_INVITE_ACCEPTED: + s_pPlatformNetworkManager->Notify(pNotification->dwNotification,pNotification->uiParam); + break; + } + + app.GetNotifications()->pop_back(); + delete pNotification; + } +#endif + s_pPlatformNetworkManager->DoWork(); + +#ifdef __ORBIS__ + if (m_pUpsell != NULL && m_pUpsell->hasResponse()) + { + int iPad_invited = m_iPlayerInvited, iPad_checking = m_pUpsell->m_userIndex; + + m_iPlayerInvited = -1; + + delete m_pUpsell; + m_pUpsell = NULL; + + if (ProfileManager.HasPlayStationPlus(iPad_checking)) + { + this->GameInviteReceived(iPad_invited, m_pInviteInfo); + + // m_pInviteInfo deleted by GameInviteReceived. + m_pInviteInfo = NULL; + } + else + { + delete m_pInviteInfo; + m_pInviteInfo = NULL; + } + } +#endif +} + +bool CGameNetworkManager::_RunNetworkGame(LPVOID lpParameter) +{ + bool success = true; + + bool isHost = g_NetworkManager.IsHost(); + // Start the network game + Minecraft *pMinecraft=Minecraft::GetInstance(); + success = StartNetworkGame(pMinecraft,lpParameter); + + if(!success) return false; + + if( isHost ) + { + // We do not have a lobby, so the only players in the game at this point are local ones. + + success = s_pPlatformNetworkManager->_RunNetworkGame(); + if(!success) + { + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE); + return true; + } + } + else + { + // Client needs QNET_STATE_GAME_PLAY so that IsInGameplay() returns true + s_pPlatformNetworkManager->SetGamePlayState(); + } + + if( g_NetworkManager.IsLeavingGame() ) return false; + + app.SetGameStarted(true); + + // 4J-PB - if this is the trial game, start the trial timer + if(!ProfileManager.IsFullVersion()) + { + ui.SetTrialTimerLimitSecs(MinecraftDynamicConfigurations::GetTrialTime()); + app.SetTrialTimerStart(); + } + //app.CloseXuiScenes(ProfileManager.GetPrimaryPad()); + + return success; +} + +bool CGameNetworkManager::StartNetworkGame(Minecraft *minecraft, LPVOID lpParameter) +{ +#ifdef _DURANGO + ProfileManager.SetDeferredSignoutEnabled(true); +#endif + + __int64 seed = 0; + if(lpParameter != NULL) + { + NetworkGameInitData *param = (NetworkGameInitData *)lpParameter; + seed = param->seed; + + app.setLevelGenerationOptions(param->levelGen); + if(param->levelGen != NULL) + { + if(app.getLevelGenerationOptions() == NULL) + { + app.DebugPrintf("Game rule was not loaded, and seed is required. Exiting.\n"); + return false; + } + else + { + param->seed = seed = app.getLevelGenerationOptions()->getLevelSeed(); + } + } + } + + static __int64 sseed = seed; // Create static version so this will be valid until next call to this function & whilst thread is running + ServerStoppedCreate(false); + if( g_NetworkManager.IsHost() ) + { + ServerStoppedCreate(true); + ServerReadyCreate(true); + // Ready to go - create actual networking thread & start hosting + C4JThread* thread = new C4JThread(&CGameNetworkManager::ServerThreadProc, lpParameter, "Server", 256 * 1024); +#if defined __PS3__ || defined __PSVITA__ + thread->SetPriority(THREAD_PRIORITY_BELOW_NORMAL); +#endif //__PS3__ + + thread->SetProcessor(CPU_CORE_SERVER); + thread->Run(); + + ServerReadyWait(); + ServerReadyDestroy(); + + if( MinecraftServer::serverHalted() ) + return false; + +// printf("Server ready to go!\n"); + } + else + { + Socket::Initialise(NULL); + } + +#ifndef _XBOX + Minecraft *pMinecraft = Minecraft::GetInstance(); + // Make sure that we have transitioned through any joining/creating stages and are actually playing the game, so that we know the players should be valid + bool changedMessage = false; + while(!IsReadyToPlayOrIdle()) + { + changedMessage = true; + pMinecraft->progressRenderer->progressStage( g_NetworkManager.CorrectErrorIDS(IDS_PROGRESS_SAVING_TO_DISC) ); // "Finalizing..." vaguest message I could find + pMinecraft->progressRenderer->progressStagePercentage( g_NetworkManager.GetJoiningReadyPercentage() ); + Sleep(10); + } + if( changedMessage ) + { + pMinecraft->progressRenderer->progressStagePercentage( 100 ); + } +#endif + + // If we aren't in session, then something bad must have happened - we aren't joining, creating or ready play + if(!IsInSession() ) + { + MinecraftServer::HaltServer(); + return false; + } + + // 4J Stu - Wait a while to make sure that DLC is loaded. This is the last point before the network communication starts + // so the latest we can check this + while( !app.DLCInstallProcessCompleted() && app.DLCInstallPending() && !g_NetworkManager.IsLeavingGame() ) + { + Sleep( 10 ); + } + if( g_NetworkManager.IsLeavingGame() ) + { + MinecraftServer::HaltServer(); + return false; + } + + // PRIMARY PLAYER + + vector createdConnections; + ClientConnection *connection; + + if( g_NetworkManager.IsHost() ) + { + connection = new ClientConnection(minecraft, NULL); + } + else + { + INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(ProfileManager.GetLockedProfile()); + if(pNetworkPlayer == NULL) + { + MinecraftServer::HaltServer(); + app.DebugPrintf("%d\n",ProfileManager.GetLockedProfile()); + // If the player is NULL here then something went wrong in the session setup, and continuing will end up in a crash + return false; + } + + Socket *socket = pNetworkPlayer->GetSocket(); + + // Fix for #13259 - CRASH: Gameplay: loading process is halted when player loads saved data + if(socket == NULL) + { + assert(false); + MinecraftServer::HaltServer(); + // If the socket is NULL here then something went wrong in the session setup, and continuing will end up in a crash + return false; + } + + connection = new ClientConnection(minecraft, socket); + } + + if( !connection->createdOk ) + { + assert(false); + delete connection; + connection = NULL; + MinecraftServer::HaltServer(); + return false; + } + + connection->send( shared_ptr( new PreLoginPacket(minecraft->user->name) ) ); + + // Tick connection until we're ready to go. The stages involved in this are: + // (1) Creating the ClientConnection sends a prelogin packet to the server + // (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet + // (3) the server sends a login back, which is handled by the client connection to start the game + if( !g_NetworkManager.IsHost() ) + { + Minecraft::GetInstance()->progressRenderer->progressStart(IDS_PROGRESS_CONNECTING); + } + else + { + // 4J Stu - Host needs to generate a unique multiplayer id for sentient telemetry reporting + INT multiplayerInstanceId = TelemetryManager->GenerateMultiplayerInstanceId(); + TelemetryManager->SetMultiplayerInstanceId(multiplayerInstanceId); + } + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + do + { + app.DebugPrintf("ticking connection A\n"); + connection->tick(); + + // 4J Stu - We were ticking this way too fast which could cause the connection to time out + // The connections should tick at 20 per second + Sleep(50); + } while ( (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame()) || tPack->isLoadingData() || (Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()) ); + ui.CleanUpSkinReload(); + + // 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash + // We need to break out of the above loop if m_bLeavingGame is set, and close the connection + if( g_NetworkManager.IsLeavingGame() || !IsInSession() ) + { + connection->close(); + } + + if( connection->isStarted() && !connection->isClosed() ) + { + createdConnections.push_back( connection ); + + int primaryPad = ProfileManager.GetPrimaryPad(); + app.SetRichPresenceContext(primaryPad,CONTEXT_GAME_STATE_BLANK); + if (GetPlayerCount() > 1) // Are we offline or online, and how many players are there + { + if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false); + else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER,false); + } + else + { + if(IsLocalGame()) ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1POFFLINE,false); + else ProfileManager.SetCurrentGameActivity(primaryPad,CONTEXT_PRESENCE_MULTIPLAYER_1P,false); + } + + + // ALL OTHER LOCAL PLAYERS + for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + // Already have setup the primary pad + if(idx == ProfileManager.GetPrimaryPad() ) continue; + + if( GetLocalPlayerByUserIndex(idx) != NULL && !ProfileManager.IsSignedIn(idx) ) + { + INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx); + Socket *socket = pNetworkPlayer->GetSocket(); + app.DebugPrintf("Closing socket due to player %d not being signed in any more\n"); + if( !socket->close(false) ) socket->close(true); + + continue; + } + + // By default when we host we only have the local player, but currently allow multiple local players to join + // when joining any other way, so just because they are signed in doesn't mean they are in the session + // 4J Stu - If they are in the session, then we should add them to the game. Otherwise we won't be able to add them later + INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(idx); + if( pNetworkPlayer == NULL ) + continue; + + ClientConnection *connection; + + Socket *socket = pNetworkPlayer->GetSocket(); + connection = new ClientConnection(minecraft, socket, idx); + + minecraft->addPendingLocalConnection(idx, connection); + //minecraft->createExtraLocalPlayer(idx, (convStringToWstring( ProfileManager.GetGamertag(idx) )).c_str(), idx, connection); + + // Open the socket on the server end to accept incoming data + Socket::addIncomingSocket(socket); + + connection->send( shared_ptr( new PreLoginPacket(convStringToWstring( ProfileManager.GetGamertag(idx) )) ) ); + + createdConnections.push_back( connection ); + + // Tick connection until we're ready to go. The stages involved in this are: + // (1) Creating the ClientConnection sends a prelogin packet to the server + // (2) the server sends a prelogin back, which is handled by the clientConnection, and returns a login packet + // (3) the server sends a login back, which is handled by the client connection to start the game + do + { + // We need to keep ticking the connections for players that already logged in + for(AUTO_VAR(it, createdConnections.begin()); it < createdConnections.end(); ++it) + { + (*it)->tick(); + } + + // 4J Stu - We were ticking this way too fast which could cause the connection to time out + // The connections should tick at 20 per second + Sleep(50); + app.DebugPrintf("<***> %d %d %d %d %d\n",IsInSession(), !connection->isStarted(),!connection->isClosed(),ProfileManager.IsSignedIn(idx),!g_NetworkManager.IsLeavingGame()); +#if defined _XBOX || __PS3__ + } while (IsInSession() && !connection->isStarted() && !connection->isClosed() && ProfileManager.IsSignedIn(idx) && !g_NetworkManager.IsLeavingGame() ); +#else + // TODO - This SHOULD be something just like the code above but temporarily changing here so that we don't have to depend on the profilemanager behaviour + } while (IsInSession() && !connection->isStarted() && !connection->isClosed() && !g_NetworkManager.IsLeavingGame() ); +#endif + + // 4J Stu - Fix for #11279 - CRASH: TCR 001: BAS Game Stability: Signing out of game will cause title to crash + // We need to break out of the above loop if m_bLeavingGame is set, and stop creating new connections + // The connections in the createdConnections vector get closed at the end of the thread + if( g_NetworkManager.IsLeavingGame() || !IsInSession() ) break; + + if( ProfileManager.IsSignedIn(idx) && !connection->isClosed() ) + { + app.SetRichPresenceContext(idx,CONTEXT_GAME_STATE_BLANK); + if (IsLocalGame()) ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYEROFFLINE,false); + else ProfileManager.SetCurrentGameActivity(idx,CONTEXT_PRESENCE_MULTIPLAYER,false); + } + else + { + connection->close(); + AUTO_VAR(it, find( createdConnections.begin(), createdConnections.end(), connection )); + if(it != createdConnections.end() ) createdConnections.erase( it ); + } + } + + app.SetGameMode( eMode_Multiplayer ); + } + else if ( connection->isClosed() || !IsInSession()) + { +// assert(false); + MinecraftServer::HaltServer(); + return false; + } + + + if(g_NetworkManager.IsLeavingGame() || !IsInSession() ) + { + for(AUTO_VAR(it, createdConnections.begin()); it < createdConnections.end(); ++it) + { + (*it)->close(); + } +// assert(false); + MinecraftServer::HaltServer(); + return false; + } + + // Catch in-case server has been halted (by a player signout). + if ( MinecraftServer::serverHalted() ) + return false; + + return true; +} + +int CGameNetworkManager::CorrectErrorIDS(int IDS) +{ + return s_pPlatformNetworkManager->CorrectErrorIDS(IDS); +} + +int CGameNetworkManager::GetLocalPlayerMask(int playerIndex) +{ + return s_pPlatformNetworkManager->GetLocalPlayerMask( playerIndex ); +} + +int CGameNetworkManager::GetPlayerCount() +{ + return s_pPlatformNetworkManager->GetPlayerCount(); +} + +int CGameNetworkManager::GetOnlinePlayerCount() +{ + return s_pPlatformNetworkManager->GetOnlinePlayerCount(); +} + +bool CGameNetworkManager::AddLocalPlayerByUserIndex( int userIndex ) +{ + return s_pPlatformNetworkManager->AddLocalPlayerByUserIndex( userIndex ); +} + +bool CGameNetworkManager::RemoveLocalPlayerByUserIndex( int userIndex ) +{ + return s_pPlatformNetworkManager->RemoveLocalPlayerByUserIndex( userIndex ); +} + +INetworkPlayer *CGameNetworkManager::GetLocalPlayerByUserIndex(int userIndex ) +{ + return s_pPlatformNetworkManager->GetLocalPlayerByUserIndex( userIndex ); +} + +INetworkPlayer *CGameNetworkManager::GetPlayerByIndex(int playerIndex) +{ + return s_pPlatformNetworkManager->GetPlayerByIndex( playerIndex ); +} + +INetworkPlayer *CGameNetworkManager::GetPlayerByXuid(PlayerUID xuid) +{ + return s_pPlatformNetworkManager->GetPlayerByXuid( xuid ); +} + +INetworkPlayer *CGameNetworkManager::GetPlayerBySmallId(unsigned char smallId) +{ + return s_pPlatformNetworkManager->GetPlayerBySmallId( smallId ); +} + +#ifdef _DURANGO +wstring CGameNetworkManager::GetDisplayNameByGamertag(wstring gamertag) +{ + return s_pPlatformNetworkManager->GetDisplayNameByGamertag(gamertag); +} +#endif + +INetworkPlayer *CGameNetworkManager::GetHostPlayer() +{ + return s_pPlatformNetworkManager->GetHostPlayer(); +} + +void CGameNetworkManager::RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) +{ + s_pPlatformNetworkManager->RegisterPlayerChangedCallback( iPad, callback, callbackParam ); +} + +void CGameNetworkManager::UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) +{ + s_pPlatformNetworkManager->UnRegisterPlayerChangedCallback( iPad, callback, callbackParam ); +} + +void CGameNetworkManager::HandleSignInChange() +{ + s_pPlatformNetworkManager->HandleSignInChange(); +} + +bool CGameNetworkManager::ShouldMessageForFullSession() +{ + return s_pPlatformNetworkManager->ShouldMessageForFullSession(); +} + +bool CGameNetworkManager::IsInSession() +{ + return s_pPlatformNetworkManager->IsInSession(); +} + +bool CGameNetworkManager::IsInGameplay() +{ + return s_pPlatformNetworkManager->IsInGameplay(); +} + +bool CGameNetworkManager::IsReadyToPlayOrIdle() +{ + return s_pPlatformNetworkManager->IsReadyToPlayOrIdle(); +} + +bool CGameNetworkManager::IsLeavingGame() +{ + return s_pPlatformNetworkManager->IsLeavingGame(); +} + +bool CGameNetworkManager::SetLocalGame(bool isLocal) +{ + return s_pPlatformNetworkManager->SetLocalGame( isLocal ); +} + +bool CGameNetworkManager::IsLocalGame() +{ + return s_pPlatformNetworkManager->IsLocalGame(); +} + +void CGameNetworkManager::SetPrivateGame(bool isPrivate) +{ + s_pPlatformNetworkManager->SetPrivateGame( isPrivate ); +} + +bool CGameNetworkManager::IsPrivateGame() +{ + return s_pPlatformNetworkManager->IsPrivateGame(); +} + +void CGameNetworkManager::HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots, unsigned char privateSlots) +{ + // 4J Stu - clear any previous connection errors + Minecraft::GetInstance()->clearConnectionFailed(); + + s_pPlatformNetworkManager->HostGame( localUsersMask, bOnlineGame, bIsPrivate, publicSlots, privateSlots ); +} + +bool CGameNetworkManager::IsHost() +{ + return (s_pPlatformNetworkManager->IsHost() == TRUE); +} + +bool CGameNetworkManager::IsInStatsEnabledSession() +{ + return s_pPlatformNetworkManager->IsInStatsEnabledSession(); +} + +bool CGameNetworkManager::SessionHasSpace(unsigned int spaceRequired) +{ + return s_pPlatformNetworkManager->SessionHasSpace( spaceRequired ); +} + +vector *CGameNetworkManager::GetSessionList(int iPad, int localPlayers, bool partyOnly) +{ + return s_pPlatformNetworkManager->GetSessionList( iPad, localPlayers, partyOnly ); +} + +bool CGameNetworkManager::GetGameSessionInfo(int iPad, SessionID sessionId,FriendSessionInfo *foundSession) +{ + return s_pPlatformNetworkManager->GetGameSessionInfo( iPad, sessionId, foundSession ); +} + +void CGameNetworkManager::SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam ) +{ + s_pPlatformNetworkManager->SetSessionsUpdatedCallback( SessionsUpdatedCallback, pSearchParam ); +} + +void CGameNetworkManager::GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ) +{ + s_pPlatformNetworkManager->GetFullFriendSessionInfo(foundSession, FriendSessionUpdatedFn, pParam); +} + +void CGameNetworkManager::ForceFriendsSessionRefresh() +{ + s_pPlatformNetworkManager->ForceFriendsSessionRefresh(); +} + +bool CGameNetworkManager::JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo) +{ + return s_pPlatformNetworkManager->JoinGameFromInviteInfo( userIndex, userMask, pInviteInfo ); +} + +CGameNetworkManager::eJoinGameResult CGameNetworkManager::JoinGame(FriendSessionInfo *searchResult, int localUsersMask) +{ + app.SetTutorialMode( false ); + g_NetworkManager.SetLocalGame(false); + + int primaryUserIndex = ProfileManager.GetLockedProfile(); + + // 4J-PB - clear any previous connection errors + Minecraft::GetInstance()->clearConnectionFailed(); + + // Make sure that the Primary Pad is in by default + localUsersMask |= GetLocalPlayerMask( ProfileManager.GetPrimaryPad() ); + + return (eJoinGameResult)(s_pPlatformNetworkManager->JoinGame( searchResult, localUsersMask, primaryUserIndex )); +} + +void CGameNetworkManager::CancelJoinGame(LPVOID lpParam) +{ +#ifdef _XBOX_ONE + s_pPlatformNetworkManager->CancelJoinGame(); +#endif +} + +bool CGameNetworkManager::LeaveGame(bool bMigrateHost) +{ + Minecraft::GetInstance()->gui->clearMessages(); + return s_pPlatformNetworkManager->LeaveGame( bMigrateHost ); +} + +int CGameNetworkManager::JoinFromInvite_SignInReturned(void *pParam,bool bContinue, int iPad) +{ + INVITE_INFO * pInviteInfo = (INVITE_INFO *)pParam; + + if(bContinue==true) + { +#ifdef __ORBIS__ + // Check if PSN is unavailable because of age restriction + int npAvailability = ProfileManager.getNPAvailability(iPad); + if (npAvailability == SCE_NP_ERROR_AGE_RESTRICTION) + { + UINT uiIDA[1]; + uiIDA[0] = IDS_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPad, NULL, NULL, app.GetStringTable()); + + return 0; + } +#endif + + app.DebugPrintf("JoinFromInvite_SignInReturned, iPad %d\n",iPad); + // It's possible that the player has not signed in - they can back out + if(ProfileManager.IsSignedIn(iPad) && ProfileManager.IsSignedInLive(iPad) ) + { + app.DebugPrintf("JoinFromInvite_SignInReturned, passed sign-in tests\n"); + int localUsersMask = 0; + int joiningUsers = 0; + + bool noPrivileges = false; + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + ++joiningUsers; + if( !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; + localUsersMask |= GetLocalPlayerMask( index ); + } + } + + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; +#if defined(__PS3__) || defined(__PSVITA__) + ProfileManager.GetChatAndContentRestrictions(iPad,false,&noUGC,NULL,NULL); +#elif defined(__ORBIS__) + ProfileManager.GetChatAndContentRestrictions(iPad,false,NULL,&noUGC,NULL); +#endif + + if(noUGC) + { + int messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + if(joiningUsers > 1) messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + + ui.RequestUGCMessageBox(IDS_CONNECTION_FAILED, messageText); + } + else if(noPrivileges) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { +#if defined(__ORBIS__) || defined(__PSVITA__) + bool chatRestricted = false; + ProfileManager.GetChatAndContentRestrictions(iPad,false,&chatRestricted,NULL,NULL); + if(chatRestricted) + { + ProfileManager.DisplaySystemMessage( 0, ProfileManager.GetPrimaryPad() ); + } +#endif + ProfileManager.SetLockedProfile(iPad); + ProfileManager.SetPrimaryPad(iPad); + + g_NetworkManager.SetLocalGame(false); + + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + + // 4J-PB - clear any previous connection errors + Minecraft::GetInstance()->clearConnectionFailed(); + + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + + bool success = g_NetworkManager.JoinGameFromInviteInfo( + iPad, // dwUserIndex + localUsersMask, // dwUserMask + pInviteInfo ); // pInviteInfo + if( !success ) + { + app.DebugPrintf( "Failed joining game from invite\n" ); + } + } + } + else + { + app.DebugPrintf("JoinFromInvite_SignInReturned, failed sign-in tests :%d %d\n",ProfileManager.IsSignedIn(iPad),ProfileManager.IsSignedInLive(iPad)); + } + } + return 0; + +} + +void CGameNetworkManager::UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving) +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + TexturePack *tPack = pMinecraft->skins->getSelected(); + s_pPlatformNetworkManager->SetSessionTexturePackParentId( tPack->getDLCParentPackId() ); + s_pPlatformNetworkManager->SetSessionSubTexturePackId( tPack->getDLCSubPackId() ); + + s_pPlatformNetworkManager->UpdateAndSetGameSessionData( pNetworkPlayerLeaving ); +} + +void CGameNetworkManager::SendInviteGUI(int quadrant) +{ + s_pPlatformNetworkManager->SendInviteGUI(quadrant); +} + +void CGameNetworkManager::ResetLeavingGame() +{ + s_pPlatformNetworkManager->ResetLeavingGame(); +} + +bool CGameNetworkManager::IsNetworkThreadRunning() +{ + return m_bNetworkThreadRunning;; +} + +int CGameNetworkManager::RunNetworkGameThreadProc( void* lpParameter ) +{ + // Share AABB & Vec3 pools with default (main thread) - should be ok as long as we don't tick the main thread whilst this thread is running + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + Tile::CreateNewThreadStorage(); + IntCache::CreateNewThreadStorage(); + + g_NetworkManager.m_bNetworkThreadRunning = true; + bool success = g_NetworkManager._RunNetworkGame(lpParameter); + g_NetworkManager.m_bNetworkThreadRunning = false; + if( !success) + { + TexturePack *tPack = Minecraft::GetInstance()->skins->getSelected(); + while ( tPack->isLoadingData() || (Minecraft::GetInstance()->skins->needsUIUpdate() || ui.IsReloadingSkin()) ) + { + Sleep(1); + } + ui.CleanUpSkinReload(); + if(app.GetDisconnectReason() == DisconnectPacket::eDisconnect_None) + { + app.SetDisconnectReason( DisconnectPacket::eDisconnect_ConnectionCreationFailed ); + } + // If we failed before the server started, clear the game rules. Otherwise the server will clear it up. + if(MinecraftServer::getInstance() == NULL) app.m_gameRules.unloadCurrentGameRules(); + Tile::ReleaseThreadStorage(); + return -1; + } + +#ifdef __PSVITA__ + // 4J-JEV: Wait for the loading/saving to finish. + while (StorageManager.GetSaveState() != C4JStorage::ESaveGame_Idle) Sleep(10); +#endif + + Tile::ReleaseThreadStorage(); + IntCache::ReleaseThreadStorage(); + return 0; +} + +int CGameNetworkManager::ServerThreadProc( void* lpParameter ) +{ + __int64 seed = 0; + if(lpParameter != NULL) + { + NetworkGameInitData *param = (NetworkGameInitData *)lpParameter; + seed = param->seed; + app.SetGameHostOption(eGameHostOption_All,param->settings); + } + + SetThreadName(-1, "Minecraft Server thread"); + AABB::CreateNewThreadStorage(); + Vec3::CreateNewThreadStorage(); + IntCache::CreateNewThreadStorage(); + Compression::UseDefaultThreadStorage(); + OldChunkStorage::UseDefaultThreadStorage(); + Entity::useSmallIds(); + Level::enableLightingCache(); + Tile::CreateNewThreadStorage(); + + MinecraftServer::main(seed, lpParameter); //saveData, app.GetGameHostOption(eGameHostOption_All)); + + Tile::ReleaseThreadStorage(); + AABB::ReleaseThreadStorage(); + Vec3::ReleaseThreadStorage(); + IntCache::ReleaseThreadStorage(); + Level::destroyLightingCache(); + + if(lpParameter != NULL) delete lpParameter; + + return S_OK; +} + +int CGameNetworkManager::ExitAndJoinFromInviteThreadProc( void* lpParam ) +{ + // Share AABB & Vec3 pools with default (main thread) - should be ok as long as we don't tick the main thread whilst this thread is running + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + + //app.SetGameStarted(false); + +#ifndef __PSVITA__ + UIScene_PauseMenu::_ExitWorld(NULL); +#endif + + while( g_NetworkManager.IsInSession() ) + { + Sleep(1); + } + + // Xbox should always be online when receiving invites - on PS3 we need to check & ask the user to sign in +#ifndef __PS3__ + JoinFromInviteData *inviteData = (JoinFromInviteData *)lpParam; + app.SetAction(inviteData->dwUserIndex, eAppAction_JoinFromInvite, lpParam); +#else + if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) + { + JoinFromInviteData *inviteData = (JoinFromInviteData *)lpParam; + app.SetAction(inviteData->dwUserIndex, eAppAction_JoinFromInvite, lpParam); + } + else + { + UINT uiIDA[2]; + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CGameNetworkManager::MustSignInReturned_0,lpParam, app.GetStringTable()); + } +#endif + + return S_OK; +} + +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ +// This case happens when we have been returned from the game to the main menu after receiving an invite and are now trying to go back in to join the new game +// The pair of methods MustSignInReturned_0 & PSNSignInReturned_0 handle this +int CGameNetworkManager::MustSignInReturned_0(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + if(result==C4JStorage::EMessage_ResultAccept) + { +#ifdef __PS3__ + SQRNetworkManager_PS3::AttemptPSNSignIn(&CGameNetworkManager::PSNSignInReturned_0, pParam,true); +#elif defined __PSVITA__ + SQRNetworkManager_Vita::AttemptPSNSignIn(&CGameNetworkManager::PSNSignInReturned_0, pParam,true); +#elif defined __ORBIS__ + SQRNetworkManager_Orbis::AttemptPSNSignIn(&CGameNetworkManager::PSNSignInReturned_0, pParam,true); +#endif + } + else + { + app.SetAction(0,eAppAction_Idle); + ui.NavigateToHomeMenu(); + ui.UpdatePlayerBasePositions(); + } + + return 0; +} + +int CGameNetworkManager::PSNSignInReturned_0(void* pParam, bool bContinue, int iPad) +{ + JoinFromInviteData *inviteData = (JoinFromInviteData *)pParam; + + // If the invite data isn't set up yet (indicated by it being all zeroes, easiest detected via the net version), then try and get it again... this can happen if we got + // the invite whilst signed out + + if( bContinue ) + { + if(inviteData->pInviteInfo->netVersion == 0) + { +#if defined __PS3__ || defined __VITA__ + if(!SQRNetworkManager_PS3::UpdateInviteData((SQRNetworkManager::PresenceSyncInfo *)inviteData->pInviteInfo)) + { + bContinue = false; + } +#elif defined __ORBIS__ + // TODO: No Orbis equivalent (should there be?) +#endif + } + } + + if( bContinue ) + { + app.SetAction(inviteData->dwUserIndex, eAppAction_JoinFromInvite, pParam); + } + else + { + app.SetAction(inviteData->dwUserIndex,eAppAction_Idle); + ui.NavigateToHomeMenu(); + ui.UpdatePlayerBasePositions(); + } + + return 0; +} + +// This case happens when we were in the main menus when we got an invite, and weren't signed in... now can proceed with the normal flow of code for this situation +// The pair of methods MustSignInReturned_1 & PSNSignInReturned_1 handle this +int CGameNetworkManager::MustSignInReturned_1(void *pParam,int iPad,C4JStorage::EMessageResult result) +{ + if(result==C4JStorage::EMessage_ResultAccept) + { +#ifdef __PS3__ + SQRNetworkManager_PS3::AttemptPSNSignIn(&CGameNetworkManager::PSNSignInReturned_1, pParam,true); +#elif defined __PSVITA__ + SQRNetworkManager_Vita::AttemptPSNSignIn(&CGameNetworkManager::PSNSignInReturned_1, pParam,true); +#elif defined __ORBIS__ + SQRNetworkManager_Orbis::AttemptPSNSignIn(&CGameNetworkManager::PSNSignInReturned_1, pParam,true); +#endif + } + return 0; +} + +int CGameNetworkManager::PSNSignInReturned_1(void* pParam, bool bContinue, int iPad) +{ + INVITE_INFO *inviteInfo = (INVITE_INFO *)pParam; + + // If the invite data isn't set up yet (indicated by it being all zeroes, easiest detected via the net version), then try and get it again... this can happen if we got + // the invite whilst signed out + + if( bContinue ) + { + if(inviteInfo->netVersion == 0) + { +#if defined __PS3__ || defined __VITA__ + if(!SQRNetworkManager_PS3::UpdateInviteData((SQRNetworkManager::PresenceSyncInfo *)inviteInfo)) + { + bContinue = false; + } +#elif defined __ORBIS__ + // TODO: No Orbis equivalent (should there be?) +#endif + + } + } + + if( bContinue ) + { + g_NetworkManager.HandleInviteWhenInMenus(0, inviteInfo); + } + + return 0; +} +#endif + +void CGameNetworkManager::_LeaveGame() +{ + s_pPlatformNetworkManager->_LeaveGame(false, true); +} + +int CGameNetworkManager::ChangeSessionTypeThreadProc( void* lpParam ) +{ + // Share AABB & Vec3 pools with default (main thread) - should be ok as long as we don't tick the main thread whilst this thread is running + AABB::UseDefaultThreadStorage(); + Vec3::UseDefaultThreadStorage(); + Compression::UseDefaultThreadStorage(); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + MinecraftServer *pServer = MinecraftServer::getInstance(); + +#if defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__ + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + if( g_NetworkManager.m_bLastDisconnectWasLostRoomOnly ) + { + if(g_NetworkManager.m_bSignedOutofPSN) + { + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, IDS_ERROR_PSN_SIGN_OUT, uiIDA,1,ProfileManager.GetPrimaryPad()); + } + else + { + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, uiIDA,1,ProfileManager.GetPrimaryPad()); + } + } + else + { + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_CONNECTION_LOST, g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT), uiIDA,1,ProfileManager.GetPrimaryPad()); + } + + // Swap these two messages around as one is too long to display at 480 + pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); + pMinecraft->progressRenderer->progressStage( -1 ); //g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT) ); +#elif defined(_XBOX_ONE) + if( g_NetworkManager.m_bFullSessionMessageOnNextSessionChange ) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + C4JStorage::EMessageResult result = ui.RequestMessageBox( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME, IDS_IN_PARTY_SESSION_FULL, uiIDA,1,ProfileManager.GetPrimaryPad()); + pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); + pMinecraft->progressRenderer->progressStage( -1 ); + } + else + { + pMinecraft->progressRenderer->progressStartNoAbort( g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT) ); + pMinecraft->progressRenderer->progressStage( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); + } + +#else + pMinecraft->progressRenderer->progressStartNoAbort( g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT) ); + pMinecraft->progressRenderer->progressStage( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); +#endif + + while( app.GetXuiServerAction(ProfileManager.GetPrimaryPad() ) != eXuiServerAction_Idle && !MinecraftServer::serverHalted() ) + { + Sleep(10); + } + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)TRUE); + + // wait for the server to be in a non-ticking state + pServer->m_serverPausedEvent->WaitForSignal(INFINITE); + +#if defined(__PS3__) || defined(__ORBIS__) || defined __PSVITA__ + // Swap these two messages around as one is too long to display at 480 + pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); + pMinecraft->progressRenderer->progressStage( -1 ); //g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT) ); +#elif defined(_XBOX_ONE) + if( g_NetworkManager.m_bFullSessionMessageOnNextSessionChange ) + { + pMinecraft->progressRenderer->progressStartNoAbort( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); + pMinecraft->progressRenderer->progressStage( -1 ); + } + else + { + pMinecraft->progressRenderer->progressStartNoAbort( g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT) ); + pMinecraft->progressRenderer->progressStage( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); + } +#else + pMinecraft->progressRenderer->progressStartNoAbort( g_NetworkManager.CorrectErrorIDS(IDS_CONNECTION_LOST_LIVE_NO_EXIT) ); + pMinecraft->progressRenderer->progressStage( IDS_PROGRESS_CONVERTING_TO_OFFLINE_GAME ); +#endif + + pMinecraft->progressRenderer->progressStagePercentage(25); + +#ifdef _XBOX_ONE + // wait for any players that were being added, to finish doing this. On XB1, if we don't do this then there's an async thread running doing this, + // which could then finish at any inappropriate time later + while( s_pPlatformNetworkManager->IsAddingPlayer() ) + { + Sleep(1); + } +#endif + + // Null the network player of all the server players that are local, to stop them being removed from the server when removed from the session + if( pServer != NULL ) + { + PlayerList *players = pServer->getPlayers(); + for(AUTO_VAR(it, players->players.begin()); it < players->players.end(); ++it) + { + shared_ptr servPlayer = *it; + if( servPlayer->connection->isLocal() && !servPlayer->connection->isGuest() ) + { + servPlayer->connection->connection->getSocket()->setPlayer(NULL); + } + } + } + + // delete the current session - if we weren't actually disconnected fully from the network but have just lost our room, then pass a bLeaveRoom flag of false + // here as by definition we don't need to leave the room (again). This is currently only an issue for sony platforms. + if( g_NetworkManager.m_bLastDisconnectWasLostRoomOnly ) + { + s_pPlatformNetworkManager->_LeaveGame(false, false); + } + else + { + s_pPlatformNetworkManager->_LeaveGame(false, true); + } + + // wait for the current session to end + while( g_NetworkManager.IsInSession() ) + { + Sleep(1); + } + + // Reset this flag as the we don't need to know that we only lost the room only from this point onwards, the behaviour is exactly the same + g_NetworkManager.m_bLastDisconnectWasLostRoomOnly = false; + g_NetworkManager.m_bFullSessionMessageOnNextSessionChange = false; + + pMinecraft->progressRenderer->progressStagePercentage(50); + + // Defaulting to making this a local game + g_NetworkManager.SetLocalGame(true); + + // Create a new session with all the players that were in the old one + int localUsersMask = 0; + char numLocalPlayers = 0; + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) && pMinecraft->localplayers[index] != NULL ) + { + numLocalPlayers++; + localUsersMask |= GetLocalPlayerMask(index); + } + } + + s_pPlatformNetworkManager->_HostGame( localUsersMask ); + + pMinecraft->progressRenderer->progressStagePercentage(75); + + // Wait for all the local players to rejoin the session + while( g_NetworkManager.GetPlayerCount() < numLocalPlayers ) + { + Sleep(1); + } + + // Restore the network player of all the server players that are local + if( pServer != NULL ) + { + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) && pMinecraft->localplayers[index] != NULL ) + { + PlayerUID localPlayerXuid = pMinecraft->localplayers[index]->getXuid(); + + PlayerList *players = pServer->getPlayers(); + for(AUTO_VAR(it, players->players.begin()); it < players->players.end(); ++it) + { + shared_ptr servPlayer = *it; + if( servPlayer->getXuid() == localPlayerXuid ) + { + servPlayer->connection->connection->getSocket()->setPlayer( g_NetworkManager.GetLocalPlayerByUserIndex(index) ); + } + } + + // Player might have a pending connection + if (pMinecraft->m_pendingLocalConnections[index] != NULL) + { + // Update the network player + pMinecraft->m_pendingLocalConnections[index]->getConnection()->getSocket()->setPlayer(g_NetworkManager.GetLocalPlayerByUserIndex(index)); + } + } + } + } + + pMinecraft->progressRenderer->progressStagePercentage(100); + +#ifndef _XBOX + // Make sure that we have transitioned through any joining/creating stages so we're actually ready to set to play + while(!s_pPlatformNetworkManager->IsReadyToPlayOrIdle()) + { + Sleep(10); + } +#endif + + s_pPlatformNetworkManager->_StartGame(); + +#ifndef _XBOX + // Wait until the message box has been closed + while(ui.IsSceneInStack(XUSER_INDEX_ANY, eUIScene_MessageBox)) + { + Sleep(10); + } +#endif + + // Start the game again + app.SetGameStarted(true); + app.SetXuiServerAction(ProfileManager.GetPrimaryPad(),eXuiServerAction_PauseServer,(void *)FALSE); + app.SetChangingSessionType(false); + app.SetReallyChangingSessionType(false); + + return S_OK; + +} + +void CGameNetworkManager::SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index) +{ + s_pPlatformNetworkManager->SystemFlagSet( pNetworkPlayer, index ); +} + +bool CGameNetworkManager::SystemFlagGet(INetworkPlayer *pNetworkPlayer, int index) +{ + return s_pPlatformNetworkManager->SystemFlagGet( pNetworkPlayer, index ); +} + +wstring CGameNetworkManager::GatherStats() +{ + return s_pPlatformNetworkManager->GatherStats(); +} + +void CGameNetworkManager::renderQueueMeter() +{ +#ifdef _XBOX + int height = 720; + + CGameNetworkManager::byteQueue[(CGameNetworkManager::messageQueuePos) & (CGameNetworkManager::messageQueue_length - 1)] = GetHostPlayer()->GetSendQueueSizeBytes(NULL, false); + CGameNetworkManager::messageQueue[(CGameNetworkManager::messageQueuePos++) & (CGameNetworkManager::messageQueue_length - 1)] = GetHostPlayer()->GetSendQueueSizeMessages(NULL, false); + + Minecraft *pMinecraft = Minecraft::GetInstance(); + pMinecraft->gui->renderGraph(CGameNetworkManager::messageQueue_length, CGameNetworkManager::messageQueuePos, CGameNetworkManager::messageQueue, 10, 1000, CGameNetworkManager::byteQueue, 100, 25000); +#endif +} + +wstring CGameNetworkManager::GatherRTTStats() +{ + return s_pPlatformNetworkManager->GatherRTTStats(); +} + +void CGameNetworkManager::StateChange_AnyToHosting() +{ + app.DebugPrintf("Disabling Guest Signin\n"); + XEnableGuestSignin(FALSE); + Minecraft::GetInstance()->clearPendingClientTextureRequests(); +} + +void CGameNetworkManager::StateChange_AnyToJoining() +{ + app.DebugPrintf("Disabling Guest Signin\n"); + XEnableGuestSignin(FALSE); + Minecraft::GetInstance()->clearPendingClientTextureRequests(); + + ConnectionProgressParams *param = new ConnectionProgressParams(); + param->iPad = ProfileManager.GetPrimaryPad(); + param->stringId = -1; + param->showTooltips = false; + param->setFailTimer = true; + param->timerTime = CONNECTING_PROGRESS_CHECK_TIME; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(), eUIScene_ConnectingProgress, param); +} + +void CGameNetworkManager::StateChange_JoiningToIdle(CPlatformNetworkManager::eJoinFailedReason reason) +{ + DisconnectPacket::eDisconnectReason disconnectReason; + switch(reason) + { + case CPlatformNetworkManager::JOIN_FAILED_SERVER_FULL: + disconnectReason = DisconnectPacket::eDisconnect_ServerFull; + break; + case CPlatformNetworkManager::JOIN_FAILED_INSUFFICIENT_PRIVILEGES: + disconnectReason = DisconnectPacket::eDisconnect_NoMultiplayerPrivilegesJoin; + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_FailedToJoinNoPrivileges); + break; + default: + disconnectReason = DisconnectPacket::eDisconnect_ConnectionCreationFailed; + break; + }; + Minecraft::GetInstance()->connectionDisconnected(ProfileManager.GetPrimaryPad(), disconnectReason); +} + +void CGameNetworkManager::StateChange_AnyToStarting() +{ +#if defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ + app.getRemoteStorage()->shutdown(); // shut the remote storage lib down and hopefully get our 7mb back +#endif + + if(!g_NetworkManager.IsHost()) + { + LoadingInputParams *loadingParams = new LoadingInputParams(); + loadingParams->func = &CGameNetworkManager::RunNetworkGameThreadProc; + loadingParams->lpParam = NULL; + + UIFullscreenProgressCompletionData *completionData = new UIFullscreenProgressCompletionData(); + completionData->bShowBackground=TRUE; + completionData->bShowLogo=TRUE; + completionData->type = e_ProgressCompletion_CloseAllPlayersUIScenes; + completionData->iPad = ProfileManager.GetPrimaryPad(); + loadingParams->completionData = completionData; + + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_FullscreenProgress, loadingParams); + } +} + +void CGameNetworkManager::StateChange_AnyToEnding(bool bStateWasPlaying) +{ + // Kick off a stats write for players that are signed into LIVE, if this is a local game + if( bStateWasPlaying && g_NetworkManager.IsLocalGame() ) + { + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + INetworkPlayer *pNetworkPlayer = g_NetworkManager.GetLocalPlayerByUserIndex(i); + if(pNetworkPlayer != NULL && ProfileManager.IsSignedIn( i ) ) + { + app.DebugPrintf("Stats save for an offline game for the player at index %d\n", i ); + Minecraft::GetInstance()->forceStatsSave(pNetworkPlayer->GetUserIndex()); + } + } + } + + Minecraft::GetInstance()->gui->clearMessages(); + + if(!g_NetworkManager.IsHost() && !g_NetworkManager.IsLeavingGame() ) + { + // 4J Stu - If the host is saving then it might take a while to quite the session, so do it ourself + //m_bLeavingGame = true; + + // The host has notified that the game is about to end + if(app.GetDisconnectReason() == DisconnectPacket::eDisconnect_None) app.SetDisconnectReason( DisconnectPacket::eDisconnect_Quitting ); + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE); + } +} + +void CGameNetworkManager::StateChange_AnyToIdle() +{ + app.DebugPrintf("Enabling Guest Signin\n"); + XEnableGuestSignin(TRUE); + // Reset this here so that we can search for games again + // 4J Stu - If we are changing session type there is a race between that thread setting the game to local, and this setting it to not local + if(!app.GetChangingSessionType()) g_NetworkManager.SetLocalGame( false ); + +} + +void CGameNetworkManager::CreateSocket( INetworkPlayer *pNetworkPlayer, bool localPlayer ) +{ + Minecraft *pMinecraft = Minecraft::GetInstance(); + + Socket *socket = NULL; + int userIdx = pNetworkPlayer->GetUserIndex(); + shared_ptr mpPlayer = (userIdx >= 0 && userIdx < XUSER_MAX_COUNT) ? pMinecraft->localplayers[userIdx] : nullptr; + if( localPlayer && mpPlayer != NULL && mpPlayer->connection != NULL) + { + // If we already have a MultiplayerLocalPlayer here then we are doing a session type change + socket = mpPlayer->connection->getSocket(); + + // Pair this socket and network player + pNetworkPlayer->SetSocket( socket); + if( socket ) + { + socket->setPlayer( pNetworkPlayer ); + } + } + else + { + socket = new Socket( pNetworkPlayer, g_NetworkManager.IsHost(), g_NetworkManager.IsHost() && localPlayer ); + pNetworkPlayer->SetSocket( socket ); + + // 4J Stu - May be other states we want to accept aswell + // Add this user to the game server if the game is started already + if( g_NetworkManager.IsHost() && g_NetworkManager.IsInGameplay() ) + { + Socket::addIncomingSocket(socket); + } + + // If this is a local player and we are already in the game, we need to setup a local connection and log + // the player in to the game server + if( localPlayer && g_NetworkManager.IsInGameplay() ) + { + int idx = pNetworkPlayer->GetUserIndex(); + app.DebugPrintf("Creating new client connection for idx: %d\n", idx); + + ClientConnection *connection; + connection = new ClientConnection(pMinecraft, socket, idx); + + if( connection->createdOk ) + { + connection->send( shared_ptr( new PreLoginPacket( pNetworkPlayer->GetOnlineName() ) ) ); + pMinecraft->addPendingLocalConnection(idx, connection); + } + else + { + pMinecraft->connectionDisconnected( idx , DisconnectPacket::eDisconnect_ConnectionCreationFailed ); + delete connection; + connection = NULL; + } + } + } + +} + +void CGameNetworkManager::CloseConnection( INetworkPlayer *pNetworkPlayer ) +{ + MinecraftServer *server = MinecraftServer::getInstance(); + if( server != NULL ) + { + PlayerList *players = server->getPlayers(); + if( players != NULL ) + { + players->closePlayerConnectionBySmallId(pNetworkPlayer->GetSmallId()); + } + } +} + +void CGameNetworkManager::PlayerJoining( INetworkPlayer *pNetworkPlayer ) +{ + if (g_NetworkManager.IsInGameplay()) // 4J-JEV: Wait to do this at StartNetworkGame if not in-game yet. + { + // 4J-JEV: Update RichPresence when a player joins the game. + bool multiplayer = g_NetworkManager.GetPlayerCount() > 1, localgame = g_NetworkManager.IsLocalGame(); + for (int iPad=0; iPadIsLocal() ) + { + TelemetryManager->RecordPlayerSessionStart(pNetworkPlayer->GetUserIndex()); + } +#ifdef _XBOX + else + { + if( !pNetworkPlayer->IsHost() ) + { + for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if(Minecraft::GetInstance()->localplayers[idx] != NULL) + { + TelemetryManager->RecordLevelStart(idx, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->level->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount()); + } + } + } + } +#endif +} + +void CGameNetworkManager::PlayerLeaving( INetworkPlayer *pNetworkPlayer ) +{ + if( pNetworkPlayer->IsLocal() ) + { + ProfileManager.SetCurrentGameActivity(pNetworkPlayer->GetUserIndex(),CONTEXT_PRESENCE_IDLE,false); + + TelemetryManager->RecordPlayerSessionExit(pNetworkPlayer->GetUserIndex(), app.GetDisconnectReason()); + } +#ifdef _XBOX + else + { + for(int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if(Minecraft::GetInstance()->localplayers[idx] != NULL) + { + TelemetryManager->RecordLevelStart(idx, eSen_FriendOrMatch_Playing_With_Invited_Friends, eSen_CompeteOrCoop_Coop_and_Competitive, Minecraft::GetInstance()->level->difficulty, app.GetLocalPlayerCount(), g_NetworkManager.GetOnlinePlayerCount()); + } + } + } +#endif +} + +void CGameNetworkManager::HostChanged() +{ + // Disable host migration + app.SetAction(ProfileManager.GetPrimaryPad(),eAppAction_ExitWorld,(void *)TRUE); +} + +void CGameNetworkManager::WriteStats( INetworkPlayer *pNetworkPlayer ) +{ + Minecraft::GetInstance()->forceStatsSave( pNetworkPlayer->GetUserIndex() ); +} + +void CGameNetworkManager::GameInviteReceived( int userIndex, const INVITE_INFO *pInviteInfo) +{ +#ifdef __ORBIS__ + if (m_pUpsell != NULL) + { + delete pInviteInfo; + return; + } + + // Need to check we're signed in to PSN + bool isSignedInLive = true; + bool isLocalMultiplayerAvailable = app.IsLocalMultiplayerAvailable(); + int iPadNotSignedInLive = -1; + for(unsigned int i = 0; i < XUSER_MAX_COUNT; i++) + { + if (ProfileManager.IsSignedIn(i) && (i == ProfileManager.GetPrimaryPad() || isLocalMultiplayerAvailable)) + { + if (isSignedInLive && !ProfileManager.IsSignedInLive(i)) + { + // Record the first non signed in live pad + iPadNotSignedInLive = i; + } + + isSignedInLive = isSignedInLive && ProfileManager.IsSignedInLive(i); + } + } + + if (!isSignedInLive) + { + // Determine why they're not "signed in live" + + // Check if PSN is unavailable because of age restriction + int npAvailability = ProfileManager.getNPAvailability(iPadNotSignedInLive); + if (npAvailability == SCE_NP_ERROR_AGE_RESTRICTION) + { + // 4J Stu - This is a bit messy and is due to the library incorrectly returning false for IsSignedInLive if the npAvailability isn't SCE_OK + UINT uiIDA[1]; + uiIDA[0]=IDS_OK; + ui.RequestMessageBox(IDS_ONLINE_SERVICE_TITLE, IDS_CONTENT_RESTRICTION, uiIDA, 1, iPadNotSignedInLive, NULL, NULL, app.GetStringTable()); + } + else if (ProfileManager.isSignedInPSN(iPadNotSignedInLive)) + { + // Signed in to PSN but not connected (no internet access) + assert(!ProfileManager.isConnectedToPSN(iPadNotSignedInLive)); + + UINT uiIDA[1]; + uiIDA[0] = IDS_OK; + ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, iPadNotSignedInLive, NULL, NULL, app.GetStringTable()); + } + else + { + // Not signed in to PSN + UINT uiIDA[1]; + uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT; + ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, iPadNotSignedInLive, &CGameNetworkManager::MustSignInReturned_1, (void *)pInviteInfo, app.GetStringTable(), NULL, 0, false); + } + return; + } + + // 4J-JEV: Check that all players are authorised for PsPlus, present upsell to players that aren't and try again. + for (unsigned int index = 0; index < XUSER_MAX_COUNT; index++) + { + if ( ProfileManager.IsSignedIn(index) + && !ProfileManager.HasPlayStationPlus(userIndex) ) + { + m_pInviteInfo = (INVITE_INFO *) pInviteInfo; + m_iPlayerInvited = userIndex; + + m_pUpsell = new PsPlusUpsellWrapper(index); + m_pUpsell->displayUpsell(); + + return; + } + } +#endif + +#ifdef __PSVITA__ + // Need to check we're signed in to PSN + bool isSignedInLive = ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad()); + if (!isSignedInLive) + { + // Determine why they're not "signed in live" + // MGH - we need to add a new message at some point for connecting when already signed in +// if (ProfileManager.IsSignedInPSN(ProfileManager.GetPrimaryPad())) +// { +// // Signed in to PSN but not connected (no internet access) +// UINT uiIDA[1]; +// uiIDA[0] = IDS_OK; +// ui.RequestMessageBox( IDS_ERROR_NETWORK_TITLE, IDS_ERROR_NETWORK, uiIDA, 1, ProfileManager.GetPrimaryPad(), NULL, NULL, app.GetStringTable()); +// } +// else + { + // Not signed in to PSN + UINT uiIDA[1]; + uiIDA[0] = IDS_PRO_NOTONLINE_ACCEPT; + ui.RequestMessageBox( IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 1, ProfileManager.GetPrimaryPad(), &CGameNetworkManager::MustSignInReturned_1, (void *)pInviteInfo, app.GetStringTable(), NULL, 0, false); + } + return; + } +#endif + + + int localUsersMask = 0; + Minecraft *pMinecraft = Minecraft::GetInstance(); + int joiningUsers = 0; + + bool noPrivileges = false; + for(unsigned int index = 0; index < XUSER_MAX_COUNT; ++index) + { + if(ProfileManager.IsSignedIn(index) ) + { + // 4J-PB we shouldn't bring any inactive players into the game, except for the invited player (who may be an inactive player) + // 4J Stu - If we are not in a game, then bring in all players signed in + if(index==userIndex || pMinecraft->localplayers[index]!=NULL ) + { + ++joiningUsers; + if( !ProfileManager.AllowedToPlayMultiplayer(index) ) noPrivileges = true; + localUsersMask |= GetLocalPlayerMask( index ); + } + } + } + + // Check if user-created content is allowed, as we cannot play multiplayer if it's not + bool noUGC = false; + bool bContentRestricted=false; + BOOL pccAllowed = TRUE; + BOOL pccFriendsAllowed = TRUE; +#if defined(__PS3__) || defined(__PSVITA__) + ProfileManager.GetChatAndContentRestrictions(userIndex,false,&noUGC,&bContentRestricted,NULL); +#else + ProfileManager.AllowedPlayerCreatedContent(ProfileManager.GetPrimaryPad(),false,&pccAllowed,&pccFriendsAllowed); + if(!pccAllowed && !pccFriendsAllowed) noUGC = true; +#endif + +#if defined(_XBOX) || defined(__PS3__) + if(joiningUsers > 1 && !RenderManager.IsHiDef() && userIndex != ProfileManager.GetPrimaryPad()) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + // 4J-PB - it's possible there is no primary pad here, when accepting an invite from the dashboard + ui.RequestMessageBox( IDS_CONNECTION_FAILED, IDS_CONNECTION_FAILED_NO_SD_SPLITSCREEN, uiIDA,1,XUSER_INDEX_ANY,NULL,NULL, app.GetStringTable()); + } + else +#endif + + if( noUGC ) + { + int messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_SINGLE_LOCAL; + if(joiningUsers > 1) messageText = IDS_NO_USER_CREATED_CONTENT_PRIVILEGE_ALL_LOCAL; + + ui.RequestUGCMessageBox(IDS_CONNECTION_FAILED, messageText, XUSER_INDEX_ANY); + } +#if defined(__PS3__) || defined __PSVITA__ + else if(bContentRestricted) + { + int messageText = IDS_CONTENT_RESTRICTION; + if(joiningUsers > 1) messageText = IDS_CONTENT_RESTRICTION_MULTIPLAYER; + + ui.RequestContentRestrictedMessageBox(IDS_CONNECTION_FAILED, messageText, XUSER_INDEX_ANY); + } +#endif + else if(noPrivileges) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + + // 4J-PB - it's possible there is no primary pad here, when accepting an invite from the dashboard + //StorageManager.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,XUSER_INDEX_ANY,NULL,NULL, app.GetStringTable()); + } + else + { +#if defined(__ORBIS__) || defined(__PSVITA__) + bool chatRestricted = false; + ProfileManager.GetChatAndContentRestrictions(ProfileManager.GetPrimaryPad(),false,&chatRestricted,NULL,NULL); + if(chatRestricted) + { + ProfileManager.DisplaySystemMessage( SCE_MSG_DIALOG_SYSMSG_TYPE_TRC_PSN_CHAT_RESTRICTION, ProfileManager.GetPrimaryPad() ); + } +#endif + if( !g_NetworkManager.IsInSession() ) + { +#ifndef __PS3__ + HandleInviteWhenInMenus(userIndex, pInviteInfo); +#else + // PS3 is more complicated here - we need to make sure that the player is online. If they are then we can do the same as the xbox, if not we need to try and get them online and then, if they do sign in, go down the same path + if(ProfileManager.IsSignedInLive(ProfileManager.GetPrimaryPad())) + { + HandleInviteWhenInMenus(userIndex, pInviteInfo); + } + else + { + UINT uiIDA[2]; + uiIDA[0]=IDS_PRO_NOTONLINE_ACCEPT; + uiIDA[1]=IDS_PRO_NOTONLINE_DECLINE; + ui.RequestMessageBox(IDS_PRO_NOTONLINE_TITLE, IDS_PRO_NOTONLINE_TEXT, uiIDA, 2, ProfileManager.GetPrimaryPad(),&CGameNetworkManager::MustSignInReturned_1,(void *)pInviteInfo, app.GetStringTable()); + } +#endif + } + else + { + app.DebugPrintf("We are already in a multiplayer game...need to leave it\n"); + +// JoinFromInviteData *joinData = new JoinFromInviteData(); +// joinData->dwUserIndex = dwUserIndex; +// joinData->dwLocalUsersMask = dwLocalUsersMask; +// joinData->pInviteInfo = pInviteInfo; + + // tell the app to process this +#ifdef __PSVITA__ + if(((CPlatformNetworkManagerSony*)s_pPlatformNetworkManager)->checkValidInviteData(pInviteInfo)) +#endif + { + app.ProcessInvite(userIndex,localUsersMask,pInviteInfo); + } + } + } +} + +volatile bool waitHere = true; + +void CGameNetworkManager::HandleInviteWhenInMenus( int userIndex, const INVITE_INFO *pInviteInfo) +{ + // We are in the root menus somewhere + +#if 0 + while( waitHere ) + { + Sleep(1); + } +#endif + + // if this is the trial game, then we need the user to unlock the full game + if(!ProfileManager.IsFullVersion()) + { + // The marketplace will fail with the primary player set to -1 + ProfileManager.SetPrimaryPad(userIndex); + + app.SetAction(userIndex,eAppAction_DashboardTrialJoinFromInvite); + } + else + { + ProfileManager.SetPrimaryPad(userIndex); + + // 4J Stu - If we accept an invite from the main menu before going to play game we need to load the DLC + // These checks are done within the StartInstallDLCProcess - (!app.DLCInstallProcessCompleted() && !app.DLCInstallPending()) app.StartInstallDLCProcess(dwUserIndex); + app.StartInstallDLCProcess(userIndex); + + // 4J Stu - Fix for #10936 - MP Lab: TCR 001: Matchmaking: Player is stuck in a soft-locked state after selecting the guest account when prompted + // The locked profile should not be changed if we are in menus as the main player might sign out in the sign-in ui + //ProfileManager.SetLockedProfile(-1); + + if(!app.IsLocalMultiplayerAvailable()) + { + bool noPrivileges=!ProfileManager.AllowedToPlayMultiplayer(userIndex); + + if(noPrivileges) + { + UINT uiIDA[1]; + uiIDA[0]=IDS_CONFIRM_OK; + ui.RequestMessageBox( IDS_NO_MULTIPLAYER_PRIVILEGE_TITLE, IDS_NO_MULTIPLAYER_PRIVILEGE_JOIN_TEXT, uiIDA,1,ProfileManager.GetPrimaryPad(),NULL,NULL, app.GetStringTable()); + } + else + { + ProfileManager.SetLockedProfile(userIndex); + ProfileManager.SetPrimaryPad(userIndex); + + int localUsersMask=0; + localUsersMask |= GetLocalPlayerMask( userIndex ); + + // If the player was signed in before selecting play, we'll not have read the profile yet, so query the sign-in status to get this to happen + ProfileManager.QuerySigninStatus(); + + // 4J-PB - clear any previous connection errors + Minecraft::GetInstance()->clearConnectionFailed(); + + g_NetworkManager.SetLocalGame(false); + + // change the minecraft player name + Minecraft::GetInstance()->user->name = convStringToWstring( ProfileManager.GetGamertag(ProfileManager.GetPrimaryPad())); + + bool success = g_NetworkManager.JoinGameFromInviteInfo( userIndex, localUsersMask, pInviteInfo ); + if( !success ) + { + app.DebugPrintf( "Failed joining game from invite\n" ); + } + } + } + else + { + // the FromInvite will make the lib decide how many panes to display based on connected pads/signed in players +#ifdef _XBOX + ProfileManager.RequestSignInUI(true, false, false, false, false,&CGameNetworkManager::JoinFromInvite_SignInReturned, (LPVOID)pInviteInfo,userIndex); +#else + SignInInfo info; + info.Func = &CGameNetworkManager::JoinFromInvite_SignInReturned; + info.lpParam = (LPVOID)pInviteInfo; + info.requireOnline = true; + app.DebugPrintf("Using fullscreen layer\n"); + ui.NavigateToScene(ProfileManager.GetPrimaryPad(),eUIScene_QuadrantSignin,&info,eUILayer_Alert,eUIGroup_Fullscreen); +#endif + } + } +} + +void CGameNetworkManager::AddLocalPlayerFailed(int idx, bool serverFull/* = false*/) +{ + Minecraft::GetInstance()->connectionDisconnected(idx, serverFull ? DisconnectPacket::eDisconnect_ServerFull : DisconnectPacket::eDisconnect_ConnectionCreationFailed); +} + +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ +void CGameNetworkManager::HandleDisconnect(bool bLostRoomOnly,bool bPSNSignout) +#else +void CGameNetworkManager::HandleDisconnect(bool bLostRoomOnly) +#endif +{ + int iPrimaryPlayer = g_NetworkManager.GetPrimaryPad(); + + if((g_NetworkManager.GetLockedProfile()!=-1) && iPrimaryPlayer!=-1 && g_NetworkManager.IsInSession() ) + { + m_bLastDisconnectWasLostRoomOnly = bLostRoomOnly; +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ + m_bSignedOutofPSN=bPSNSignout; +#endif + app.SetAction(iPrimaryPlayer,eAppAction_EthernetDisconnected); + } + else + { + m_bLastDisconnectWasLostRoomOnly = false; + } +} + +int CGameNetworkManager::GetPrimaryPad() +{ + return ProfileManager.GetPrimaryPad(); +} + +int CGameNetworkManager::GetLockedProfile() +{ + return ProfileManager.GetLockedProfile(); +} + +bool CGameNetworkManager::IsSignedInLive(int playerIdx) +{ + return ProfileManager.IsSignedInLive(playerIdx); +} + +bool CGameNetworkManager::AllowedToPlayMultiplayer(int playerIdx) +{ + return ProfileManager.AllowedToPlayMultiplayer(playerIdx); +} + +char *CGameNetworkManager::GetOnlineName(int playerIdx) +{ + return ProfileManager.GetGamertag(playerIdx); +} + +void CGameNetworkManager::ServerReadyCreate(bool create) +{ + m_hServerReadyEvent = ( create ? ( new C4JThread::Event ) : NULL ); +} + +void CGameNetworkManager::ServerReady() +{ + m_hServerReadyEvent->Set(); +} + +void CGameNetworkManager::ServerReadyWait() +{ + m_hServerReadyEvent->WaitForSignal(INFINITE); +} + +void CGameNetworkManager::ServerReadyDestroy() +{ + delete m_hServerReadyEvent; + m_hServerReadyEvent = NULL; +} + +bool CGameNetworkManager::ServerReadyValid() +{ + return ( m_hServerReadyEvent != NULL ); +} + +void CGameNetworkManager::ServerStoppedCreate(bool create) +{ + m_hServerStoppedEvent = ( create ? ( new C4JThread::Event ) : NULL ); +} + +void CGameNetworkManager::ServerStopped() +{ + m_hServerStoppedEvent->Set(); +} + +void CGameNetworkManager::ServerStoppedWait() +{ + // If this is called from the main thread, then this won't be ticking anything which can mean that the storage manager state can't progress. + // This means that the server thread we are waiting on won't ever finish, as it might be locked waiting for this to complete itself. + // Do some ticking here then if this is the case. + if( C4JThread::isMainThread() ) + { + int result = WAIT_TIMEOUT; + do + { +#ifndef _XBOX + RenderManager.StartFrame(); +#endif + result = m_hServerStoppedEvent->WaitForSignal(20); + // Tick some simple things + ProfileManager.Tick(); + StorageManager.Tick(); + InputManager.Tick(); + RenderManager.Tick(); + ui.tick(); + ui.render(); + RenderManager.Present(); + } while( result == WAIT_TIMEOUT ); + } + else + { + m_hServerStoppedEvent->WaitForSignal(INFINITE); + } +} + +void CGameNetworkManager::ServerStoppedDestroy() +{ + delete m_hServerStoppedEvent; + m_hServerStoppedEvent = NULL; +} + +bool CGameNetworkManager::ServerStoppedValid() +{ + return ( m_hServerStoppedEvent != NULL ); +} + +int CGameNetworkManager::GetJoiningReadyPercentage() +{ + return s_pPlatformNetworkManager->GetJoiningReadyPercentage(); +} + +#ifndef _XBOX +void CGameNetworkManager::FakeLocalPlayerJoined() +{ + s_pPlatformNetworkManager->FakeLocalPlayerJoined(); +} +#endif + +#ifdef __PSVITA__ +bool CGameNetworkManager::usingAdhocMode() +{ + return ((CPlatformNetworkManagerSony*)s_pPlatformNetworkManager)->usingAdhocMode(); +} + +void CGameNetworkManager::setAdhocMode(bool bAdhoc) +{ + ((CPlatformNetworkManagerSony*)s_pPlatformNetworkManager)->setAdhocMode(bAdhoc); +} + +void CGameNetworkManager::startAdhocMatching() +{ + ((CPlatformNetworkManagerSony*)s_pPlatformNetworkManager)->startAdhocMatching(); +} + +#endif diff --git a/Minecraft.Client/Common/Network/GameNetworkManager.h b/Minecraft.Client/Common/Network/GameNetworkManager.h new file mode 100644 index 0000000..1bb532d --- /dev/null +++ b/Minecraft.Client/Common/Network/GameNetworkManager.h @@ -0,0 +1,236 @@ +#pragma once +using namespace std; +#include +#include +#include "..\..\..\Minecraft.World\C4JThread.h" +#include "NetworkPlayerInterface.h" +#ifdef _XBOX +#include "..\..\Xbox\Network\PlatformNetworkManagerXbox.h" +#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ +#include "..\..\Common\Network\Sony\PlatformNetworkManagerSony.h" +#elif defined _DURANGO +#include "..\..\Durango\Network\PlatformNetworkManagerDurango.h" +#else +#include "PlatformNetworkManagerStub.h" +#endif +#include "SessionInfo.h" + +#ifdef __ORBIS__ +#include "..\..\Orbis\Network\PsPlusUpsellWrapper_Orbis.h" +#endif + +class ClientConnection; +class Minecraft; + + +// This class implements the game-side interface to the networking system. As such, it is platform independent and may contain bits of game-side code where appropriate. +// It shouldn't ever reference any platform specifics of the network implementation (eg QNET), rather it should interface with an implementation of PlatformNetworkManager to +// provide this functionality. + +class CGameNetworkManager +{ +#ifdef _XBOX + friend class CPlatformNetworkManagerXbox; +#elif defined __PS3__ || defined __ORBIS__ || defined __PSVITA__ + friend class CPlatformNetworkManagerSony; +#elif defined _DURANGO + friend class CPlatformNetworkManagerDurango; +#else + friend class CPlatformNetworkManagerStub; +#endif +public: + CGameNetworkManager(); + // Misc high level flow + + typedef enum + { + JOINGAME_SUCCESS, + JOINGAME_FAIL_GENERAL, + JOINGAME_FAIL_SERVER_FULL + } eJoinGameResult; + + void Initialise(); + void Terminate(); + void DoWork(); + bool _RunNetworkGame(LPVOID lpParameter); + bool StartNetworkGame(Minecraft *minecraft, LPVOID lpParameter); + int CorrectErrorIDS(int IDS); + + // Player management + + static int GetLocalPlayerMask(int playerIndex); + int GetPlayerCount(); + int GetOnlinePlayerCount(); + bool AddLocalPlayerByUserIndex( int userIndex ); + bool RemoveLocalPlayerByUserIndex( int userIndex ); + INetworkPlayer *GetLocalPlayerByUserIndex(int userIndex ); + INetworkPlayer *GetPlayerByIndex(int playerIndex); + INetworkPlayer *GetPlayerByXuid(PlayerUID xuid); + INetworkPlayer *GetPlayerBySmallId(unsigned char smallId); + wstring GetDisplayNameByGamertag(wstring gamertag); + INetworkPlayer *GetHostPlayer(); + void RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam); + void UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam); + void HandleSignInChange(); + bool ShouldMessageForFullSession(); + + // State management + + bool IsInSession(); + bool IsInGameplay(); + bool IsLeavingGame(); + bool IsReadyToPlayOrIdle(); + + // Hosting and game type + + bool SetLocalGame(bool isLocal); + bool IsLocalGame(); + void SetPrivateGame(bool isPrivate); + bool IsPrivateGame(); + void HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0); + bool IsHost(); + bool IsInStatsEnabledSession(); + + // Client session discovery + + bool SessionHasSpace(unsigned int spaceRequired = 1); + vector *GetSessionList(int iPad, int localPlayers, bool partyOnly); + bool GetGameSessionInfo(int iPad, SessionID sessionId,FriendSessionInfo *foundSession); + void SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam ); + void GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ); + void ForceFriendsSessionRefresh(); + + // Session joining and leaving + + bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo); + eJoinGameResult JoinGame(FriendSessionInfo *searchResult, int localUsersMask); + static void CancelJoinGame(LPVOID lpParam); // Not part of the shared interface + bool LeaveGame(bool bMigrateHost); + static int JoinFromInvite_SignInReturned(void *pParam,bool bContinue, int iPad); + void UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving = NULL); + void SendInviteGUI(int iPad); + void ResetLeavingGame(); + + // Threads + + bool IsNetworkThreadRunning(); + static int RunNetworkGameThreadProc( void* lpParameter ); + static int ServerThreadProc( void* lpParameter ); + static int ExitAndJoinFromInviteThreadProc( void* lpParam ); + +#if (defined __PS3__) || (defined __ORBIS__) || (defined __PSVITA__) + static int MustSignInReturned_0(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int PSNSignInReturned_0(void* pParam, bool bContinue, int iPad); + + static int MustSignInReturned_1(void *pParam,int iPad,C4JStorage::EMessageResult result); + static int PSNSignInReturned_1(void* pParam, bool bContinue, int iPad); +#endif + + static void _LeaveGame(); + static int ChangeSessionTypeThreadProc( void* lpParam ); + + // System flags + + void SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index); + bool SystemFlagGet(INetworkPlayer *pNetworkPlayer, int index); + + // Events + + void ServerReadyCreate(bool create); // Create the signal (or set to NULL) + void ServerReady(); // Signal that we are ready + void ServerReadyWait(); // Wait for the signal + void ServerReadyDestroy(); // Destroy signal + bool ServerReadyValid(); // Is non-NULL + + void ServerStoppedCreate(bool create); // Create the signal + void ServerStopped(); // Signal that we are ready + void ServerStoppedWait(); // Wait for the signal + void ServerStoppedDestroy(); // Destroy signal + bool ServerStoppedValid(); // Is non-NULL + +#ifdef __PSVITA__ + static bool usingAdhocMode(); + static void setAdhocMode(bool bAdhoc); + static void startAdhocMatching(); +#endif + // Debug output + + wstring GatherStats(); + void renderQueueMeter(); + wstring GatherRTTStats(); + + // GUI debug output + + // Used for debugging output + static const int messageQueue_length = 512; + static __int64 messageQueue[messageQueue_length]; + static const int byteQueue_length = 512; + static __int64 byteQueue[byteQueue_length]; + static int messageQueuePos; + + // Methods called from PlatformNetworkManager +private: + void StateChange_AnyToHosting(); + void StateChange_AnyToJoining(); + void StateChange_JoiningToIdle(CPlatformNetworkManager::eJoinFailedReason reason); + void StateChange_AnyToStarting(); + void StateChange_AnyToEnding(bool bStateWasPlaying); + void StateChange_AnyToIdle(); + void CreateSocket( INetworkPlayer *pNetworkPlayer, bool localPlayer ); + void CloseConnection( INetworkPlayer *pNetworkPlayer ); + void PlayerJoining( INetworkPlayer *pNetworkPlayer ); + void PlayerLeaving( INetworkPlayer *pNetworkPlayer ); + void HostChanged(); + void WriteStats( INetworkPlayer *pNetworkPlayer ); + void GameInviteReceived( int userIndex, const INVITE_INFO *pInviteInfo); + void HandleInviteWhenInMenus( int userIndex, const INVITE_INFO *pInviteInfo); + void AddLocalPlayerFailed(int idx, bool serverFull = false); +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ + void HandleDisconnect(bool bLostRoomOnly,bool bPSNSignOut); +#else + void HandleDisconnect(bool bLostRoomOnly); +#endif + + int GetPrimaryPad(); + int GetLockedProfile(); + bool IsSignedInLive(int playerIdx); + bool AllowedToPlayMultiplayer(int playerIdx); + char *GetOnlineName(int playerIdx); + + C4JThread::Event* m_hServerStoppedEvent; + C4JThread::Event* m_hServerReadyEvent; + bool m_bInitialised; + +#ifdef _XBOX_ONE +public: + void SetFullSessionMessageOnNextSessionChange() { m_bFullSessionMessageOnNextSessionChange = true; } +#endif +private: + float m_lastPlayerEventTimeStart; // For telemetry + static CPlatformNetworkManager *s_pPlatformNetworkManager; + bool m_bNetworkThreadRunning; + int GetJoiningReadyPercentage(); + bool m_bLastDisconnectWasLostRoomOnly; + bool m_bFullSessionMessageOnNextSessionChange; +#if defined __PS3__ || defined __PSVITA__ || defined __ORBIS__ + bool m_bSignedOutofPSN; +#endif + +#ifdef __ORBIS__ + PsPlusUpsellWrapper *m_pUpsell; + INVITE_INFO *m_pInviteInfo; + int m_iPlayerInvited; +#endif + +public: +#ifndef _XBOX + void FakeLocalPlayerJoined(); // Temporary method whilst we don't have real networking to make this happen +#endif +}; + +extern CGameNetworkManager g_NetworkManager; + +#ifdef __PS3__ +#undef __in +#define __out +#endif diff --git a/Minecraft.Client/Common/Network/NetworkPlayerInterface.h b/Minecraft.Client/Common/Network/NetworkPlayerInterface.h new file mode 100644 index 0000000..501b08f --- /dev/null +++ b/Minecraft.Client/Common/Network/NetworkPlayerInterface.h @@ -0,0 +1,31 @@ +#pragma once + +class Socket; + +// This is the platform independent interface for dealing with players within a network game. This should be used directly by game code (and GameNetworkManager) rather than the platform-specific implementations. + +class INetworkPlayer +{ +public: + virtual ~INetworkPlayer() {} + virtual unsigned char GetSmallId() = 0; + virtual void SendData(INetworkPlayer *player, const void *pvData, int dataSize, bool lowPriority) = 0; + virtual bool IsSameSystem(INetworkPlayer *player) = 0; + virtual int GetSendQueueSizeBytes( INetworkPlayer *player, bool lowPriority ) = 0; + virtual int GetSendQueueSizeMessages( INetworkPlayer *player, bool lowPriority ) = 0; + virtual int GetCurrentRtt() = 0; + virtual bool IsHost() = 0; + virtual bool IsGuest() = 0; + virtual bool IsLocal() = 0; + virtual int GetSessionIndex() = 0; + virtual bool IsTalking() = 0; + virtual bool IsMutedByLocalUser(int userIndex) = 0; + virtual bool HasVoice() = 0; + virtual bool HasCamera() = 0; + virtual int GetUserIndex() = 0; + virtual void SetSocket(Socket *pSocket) = 0; + virtual Socket *GetSocket() = 0; + virtual const wchar_t *GetOnlineName() = 0; + virtual wstring GetDisplayName() = 0; + virtual PlayerUID GetUID() = 0; +}; diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h new file mode 100644 index 0000000..31c415a --- /dev/null +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerInterface.h @@ -0,0 +1,127 @@ +#pragma once +using namespace std; +#include +#include +#include "..\..\..\Minecraft.World\C4JThread.h" +#include "NetworkPlayerInterface.h" +#include "SessionInfo.h" + +class ClientConnection; +class Minecraft; +class CGameNetworkManager; + +// This is the interface to be implemented by the platform-specific versions of the PlatformNetworkManagers. This API is used directly by GameNetworkManager so that +// it can remain as platform independent as possible. + +// This value should be incremented if the server version changes, or the game session data changes +#define MINECRAFT_NET_VERSION VER_NETWORK + + +typedef struct _SearchForGamesData +{ + DWORD sessionIDCount; + XSESSION_SEARCHRESULT_HEADER *searchBuffer; + XNQOS **ppQos; + SessionID *sessionIDList; + XOVERLAPPED *pOverlapped; +} SearchForGamesData; + +class CPlatformNetworkManager +{ + friend class CGameNetworkManager; +public: + + typedef enum + { + JOIN_FAILED_SERVER_FULL, + JOIN_FAILED_INSUFFICIENT_PRIVILEGES, + JOIN_FAILED_NONSPECIFIC, + } eJoinFailedReason; + + virtual bool Initialise(CGameNetworkManager *pGameNetworkManager, int flagIndexSize) = 0; + virtual void Terminate() = 0; + virtual int GetJoiningReadyPercentage() = 0; + virtual int CorrectErrorIDS(int IDS) = 0; + + virtual void DoWork() = 0; + virtual int GetPlayerCount() = 0; + virtual int GetOnlinePlayerCount() = 0; + virtual int GetLocalPlayerMask(int playerIndex) = 0; + virtual bool AddLocalPlayerByUserIndex( int userIndex ) = 0; + virtual bool RemoveLocalPlayerByUserIndex( int userIndex ) = 0; + virtual INetworkPlayer *GetLocalPlayerByUserIndex( int userIndex ) = 0; + virtual INetworkPlayer *GetPlayerByIndex(int playerIndex) = 0; + virtual INetworkPlayer * GetPlayerByXuid(PlayerUID xuid) = 0; + virtual INetworkPlayer * GetPlayerBySmallId(unsigned char smallId) = 0; + virtual bool ShouldMessageForFullSession() = 0; + + virtual INetworkPlayer *GetHostPlayer() = 0; + virtual bool IsHost() = 0; + virtual bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo) = 0; + virtual bool LeaveGame(bool bMigrateHost) = 0; + + virtual bool IsInSession() = 0; + virtual bool IsInGameplay() = 0; + virtual bool IsReadyToPlayOrIdle() = 0; + virtual bool IsInStatsEnabledSession() = 0; + virtual bool SessionHasSpace(unsigned int spaceRequired = 1) = 0; + virtual void SendInviteGUI(int quadrant) = 0; + virtual bool IsAddingPlayer() = 0; + + virtual void HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0) = 0; + virtual int JoinGame(FriendSessionInfo *searchResult, int dwLocalUsersMask, int dwPrimaryUserIndex ) = 0; + virtual void CancelJoinGame() {}; + virtual bool SetLocalGame(bool isLocal) = 0; + virtual bool IsLocalGame() = 0; + virtual void SetPrivateGame(bool isPrivate) = 0; + virtual bool IsPrivateGame() = 0; + virtual bool IsLeavingGame() = 0; + virtual void ResetLeavingGame() = 0; + + virtual void RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) = 0; + virtual void UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) = 0; + + virtual void HandleSignInChange() = 0; + + virtual bool _RunNetworkGame() = 0; + virtual void SetGamePlayState() {} + +private: + virtual bool _LeaveGame(bool bMigrateHost, bool bLeaveRoom) = 0; + virtual void _HostGame(int usersMask, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0) = 0; + virtual bool _StartGame() = 0; + + +public: + virtual void UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving = NULL) = 0; + +private: + virtual bool RemoveLocalPlayer( INetworkPlayer *pNetworkPlayer ) = 0; + +public: + virtual void SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index) = 0; + virtual bool SystemFlagGet(INetworkPlayer *pNetworkPlayer, int index) = 0; + + virtual wstring GatherStats() = 0; + virtual wstring GatherRTTStats() = 0; + +private: + virtual void SetSessionTexturePackParentId( int id ) = 0; + virtual void SetSessionSubTexturePackId( int id ) = 0; + virtual void Notify(int ID, ULONG_PTR Param) = 0; + +public: + virtual vector *GetSessionList(int iPad, int localPlayers, bool partyOnly) = 0; + virtual bool GetGameSessionInfo(int iPad, SessionID sessionId,FriendSessionInfo *foundSession) = 0; + virtual void SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam ) = 0; + virtual void GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ) = 0; + virtual void ForceFriendsSessionRefresh() = 0; + +#ifndef _XBOX + virtual void FakeLocalPlayerJoined() {}; // Temporary method whilst we don't have real networking to make this happen +#endif + +#ifdef _DURANGO + virtual wstring GetDisplayNameByGamertag(wstring gamertag) = 0; +#endif +}; diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp new file mode 100644 index 0000000..24d5243 --- /dev/null +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.cpp @@ -0,0 +1,859 @@ +#include "stdafx.h" +#include "..\..\..\Minecraft.World\Socket.h" +#include "..\..\..\Minecraft.World\StringHelpers.h" +#include "PlatformNetworkManagerStub.h" +#include "..\..\Xbox\Network\NetworkPlayerXbox.h" +#ifdef _WINDOWS64 +#include "..\..\Windows64\Network\WinsockNetLayer.h" +#include "..\..\Minecraft.h" +#include "..\..\User.h" +#endif + +CPlatformNetworkManagerStub *g_pPlatformNetworkManager; + + +void CPlatformNetworkManagerStub::NotifyPlayerJoined(IQNetPlayer *pQNetPlayer ) +{ + const char * pszDescription; + + // 4J Stu - We create a fake socket for every where that we need an INBOUND queue of game data. Outbound + // is all handled by QNet so we don't need that. Therefore each client player has one, and the host has one + // for each client player. + bool createFakeSocket = false; + bool localPlayer = false; + + NetworkPlayerXbox *networkPlayer = (NetworkPlayerXbox *)addNetworkPlayer(pQNetPlayer); + + if( pQNetPlayer->IsLocal() ) + { + localPlayer = true; + if( pQNetPlayer->IsHost() ) + { + pszDescription = "local host"; + // 4J Stu - No socket for the localhost as it uses a special loopback queue + + m_machineQNetPrimaryPlayers.push_back( pQNetPlayer ); + } + else + { + pszDescription = "local"; + + // We need an inbound queue on all local players to receive data from the host + createFakeSocket = true; + } + } + else + { + if( pQNetPlayer->IsHost() ) + { + pszDescription = "remote host"; + } + else + { + pszDescription = "remote"; + + // If we are the host, then create a fake socket for every remote player + if( m_pIQNet->IsHost() ) + { + createFakeSocket = true; + } + } + + if( m_pIQNet->IsHost() && !m_bHostChanged ) + { + // Do we already have a primary player for this system? + bool systemHasPrimaryPlayer = false; + for(AUTO_VAR(it, m_machineQNetPrimaryPlayers.begin()); it < m_machineQNetPrimaryPlayers.end(); ++it) + { + IQNetPlayer *pQNetPrimaryPlayer = *it; + if( pQNetPlayer->IsSameSystem(pQNetPrimaryPlayer) ) + { + systemHasPrimaryPlayer = true; + break; + } + } + if( !systemHasPrimaryPlayer ) + m_machineQNetPrimaryPlayers.push_back( pQNetPlayer ); + } + } + g_NetworkManager.PlayerJoining( networkPlayer ); + + if( createFakeSocket == true && !m_bHostChanged ) + { + g_NetworkManager.CreateSocket( networkPlayer, localPlayer ); + } + + app.DebugPrintf( "Player 0x%p \"%ls\" joined; %s; voice %i; camera %i.\n", + pQNetPlayer, + pQNetPlayer->GetGamertag(), + pszDescription, + (int) pQNetPlayer->HasVoice(), + (int) pQNetPlayer->HasCamera() ); + + + if( m_pIQNet->IsHost() ) + { + // 4J-PB - only the host should do this +// g_NetworkManager.UpdateAndSetGameSessionData(); + SystemFlagAddPlayer( networkPlayer ); + } + + for( int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if(playerChangedCallback[idx] != NULL) + playerChangedCallback[idx]( playerChangedCallbackParam[idx], networkPlayer, false ); + } + + if(m_pIQNet->GetState() == QNET_STATE_GAME_PLAY) + { + int localPlayerCount = 0; + for(unsigned int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if( m_pIQNet->GetLocalPlayerByUserIndex(idx) != NULL ) ++localPlayerCount; + } + + float appTime = app.getAppTime(); + + // Only record stats for the primary player here + m_lastPlayerEventTimeStart = appTime; + } +} + +void CPlatformNetworkManagerStub::NotifyPlayerLeaving(IQNetPlayer *pQNetPlayer) +{ + app.DebugPrintf("Player 0x%p \"%ls\" leaving.\n", pQNetPlayer, pQNetPlayer->GetGamertag()); + + INetworkPlayer *networkPlayer = getNetworkPlayer(pQNetPlayer); + if (networkPlayer == NULL) + return; + + Socket *socket = networkPlayer->GetSocket(); + if (socket != NULL) + { + if (m_pIQNet->IsHost()) + g_NetworkManager.CloseConnection(networkPlayer); + } + + if (m_pIQNet->IsHost()) + { + SystemFlagRemovePlayer(networkPlayer); + } + + g_NetworkManager.PlayerLeaving(networkPlayer); + + for (int idx = 0; idx < XUSER_MAX_COUNT; ++idx) + { + if (playerChangedCallback[idx] != NULL) + playerChangedCallback[idx](playerChangedCallbackParam[idx], networkPlayer, true); + } + + removeNetworkPlayer(pQNetPlayer); +} + +bool CPlatformNetworkManagerStub::Initialise(CGameNetworkManager *pGameNetworkManager, int flagIndexSize) +{ + m_pGameNetworkManager = pGameNetworkManager; + m_flagIndexSize = flagIndexSize; + m_pIQNet = new IQNet(); + g_pPlatformNetworkManager = this; + for( int i = 0; i < XUSER_MAX_COUNT; i++ ) + { + playerChangedCallback[ i ] = NULL; + } + + m_bLeavingGame = false; + m_bLeaveGameOnTick = false; + m_bHostChanged = false; + + m_bSearchResultsReady = false; + m_bSearchPending = false; + + m_bIsOfflineGame = false; + m_pSearchParam = NULL; + m_SessionsUpdatedCallback = NULL; + + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + m_searchResultsCount[i] = 0; + m_lastSearchStartTime[i] = 0; + + // The results that will be filled in with the current search + m_pSearchResults[i] = NULL; + m_pQoSResult[i] = NULL; + m_pCurrentSearchResults[i] = NULL; + m_pCurrentQoSResult[i] = NULL; + m_currentSearchResultsCount[i] = 0; + } + + // Success! + return true; +} + +void CPlatformNetworkManagerStub::Terminate() +{ +} + +int CPlatformNetworkManagerStub::GetJoiningReadyPercentage() +{ + return 100; +} + +int CPlatformNetworkManagerStub::CorrectErrorIDS(int IDS) +{ + return IDS; +} + +bool CPlatformNetworkManagerStub::isSystemPrimaryPlayer(IQNetPlayer *pQNetPlayer) +{ + return true; +} + +// We call this twice a frame, either side of the render call so is a good place to "tick" things +void CPlatformNetworkManagerStub::DoWork() +{ +#ifdef _WINDOWS64 + extern QNET_STATE _iQNetStubState; + if (_iQNetStubState == QNET_STATE_SESSION_STARTING && app.GetGameStarted()) + { + _iQNetStubState = QNET_STATE_GAME_PLAY; + if (m_pIQNet->IsHost()) + WinsockNetLayer::UpdateAdvertiseJoinable(true); + } + if (_iQNetStubState == QNET_STATE_IDLE) + TickSearch(); + if (_iQNetStubState == QNET_STATE_GAME_PLAY && m_pIQNet->IsHost()) + { + BYTE disconnectedSmallId; + while (WinsockNetLayer::PopDisconnectedSmallId(&disconnectedSmallId)) + { + IQNetPlayer *qnetPlayer = m_pIQNet->GetPlayerBySmallId(disconnectedSmallId); + if (qnetPlayer != NULL && qnetPlayer->m_smallId == disconnectedSmallId) + { + NotifyPlayerLeaving(qnetPlayer); + qnetPlayer->m_smallId = 0; + qnetPlayer->m_isRemote = false; + qnetPlayer->m_isHostPlayer = false; + qnetPlayer->m_gamertag[0] = 0; + qnetPlayer->SetCustomDataValue(0); + WinsockNetLayer::PushFreeSmallId(disconnectedSmallId); + if (IQNet::s_playerCount > 1) + IQNet::s_playerCount--; + } + } + } +#endif +} + +int CPlatformNetworkManagerStub::GetPlayerCount() +{ + return m_pIQNet->GetPlayerCount(); +} + +bool CPlatformNetworkManagerStub::ShouldMessageForFullSession() +{ + return false; +} + +int CPlatformNetworkManagerStub::GetOnlinePlayerCount() +{ + return 1; +} + +int CPlatformNetworkManagerStub::GetLocalPlayerMask(int playerIndex) +{ + return 1 << playerIndex; +} + +bool CPlatformNetworkManagerStub::AddLocalPlayerByUserIndex( int userIndex ) +{ + NotifyPlayerJoined(m_pIQNet->GetLocalPlayerByUserIndex(userIndex)); + return ( m_pIQNet->AddLocalPlayerByUserIndex(userIndex) == S_OK ); +} + +bool CPlatformNetworkManagerStub::RemoveLocalPlayerByUserIndex( int userIndex ) +{ + return true; +} + +bool CPlatformNetworkManagerStub::IsInStatsEnabledSession() +{ + return true; +} + +bool CPlatformNetworkManagerStub::SessionHasSpace(unsigned int spaceRequired /*= 1*/) +{ + return true; +} + +void CPlatformNetworkManagerStub::SendInviteGUI(int quadrant) +{ +} + +bool CPlatformNetworkManagerStub::IsAddingPlayer() +{ + return false; +} + +bool CPlatformNetworkManagerStub::LeaveGame(bool bMigrateHost) +{ + if( m_bLeavingGame ) return true; + + m_bLeavingGame = true; + +#ifdef _WINDOWS64 + WinsockNetLayer::StopAdvertising(); +#endif + + if(m_pIQNet->IsHost() && g_NetworkManager.ServerStoppedValid()) + { + m_pIQNet->EndGame(); + g_NetworkManager.ServerStoppedWait(); + g_NetworkManager.ServerStoppedDestroy(); + } + else + { + m_pIQNet->EndGame(); + } + + for (AUTO_VAR(it, currentNetworkPlayers.begin()); it != currentNetworkPlayers.end(); it++) + delete *it; + currentNetworkPlayers.clear(); + m_machineQNetPrimaryPlayers.clear(); + SystemFlagReset(); + +#ifdef _WINDOWS64 + WinsockNetLayer::Shutdown(); + WinsockNetLayer::Initialize(); +#endif + + return true; +} + +bool CPlatformNetworkManagerStub::_LeaveGame(bool bMigrateHost, bool bLeaveRoom) +{ + return true; +} + +void CPlatformNetworkManagerStub::HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots /*= MINECRAFT_NET_MAX_PLAYERS*/, unsigned char privateSlots /*= 0*/) +{ + SetLocalGame( !bOnlineGame ); + SetPrivateGame( bIsPrivate ); + SystemFlagReset(); + + localUsersMask |= GetLocalPlayerMask( g_NetworkManager.GetPrimaryPad() ); + + m_bLeavingGame = false; + + m_pIQNet->HostGame(); + +#ifdef _WINDOWS64 + IQNet::m_player[0].m_smallId = 0; + IQNet::m_player[0].m_isRemote = false; + IQNet::m_player[0].m_isHostPlayer = true; + IQNet::s_playerCount = 1; +#endif + + _HostGame( localUsersMask, publicSlots, privateSlots ); + +#ifdef _WINDOWS64 + int port = WIN64_NET_DEFAULT_PORT; + if (!WinsockNetLayer::IsActive()) + WinsockNetLayer::HostGame(port); + + const wchar_t *hostName = IQNet::m_player[0].m_gamertag; + unsigned int settings = app.GetGameHostOption(eGameHostOption_All); + WinsockNetLayer::StartAdvertising(port, hostName, settings, 0, 0, MINECRAFT_NET_VERSION); +#endif +} + +void CPlatformNetworkManagerStub::_HostGame(int usersMask, unsigned char publicSlots /*= MINECRAFT_NET_MAX_PLAYERS*/, unsigned char privateSlots /*= 0*/) +{ +} + +bool CPlatformNetworkManagerStub::_StartGame() +{ + return true; +} + +int CPlatformNetworkManagerStub::JoinGame(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex) +{ +#ifdef _WINDOWS64 + if (searchResult == NULL) + return CGameNetworkManager::JOINGAME_FAIL_GENERAL; + + const char *hostIP = searchResult->data.hostIP; + int hostPort = searchResult->data.hostPort; + + if (hostPort <= 0 || hostIP[0] == 0) + return CGameNetworkManager::JOINGAME_FAIL_GENERAL; + + m_bLeavingGame = false; + IQNet::s_isHosting = false; + m_pIQNet->ClientJoinGame(); + + IQNet::m_player[0].m_smallId = 0; + IQNet::m_player[0].m_isRemote = true; + IQNet::m_player[0].m_isHostPlayer = true; + wcsncpy_s(IQNet::m_player[0].m_gamertag, 32, searchResult->data.hostName, _TRUNCATE); + + WinsockNetLayer::StopDiscovery(); + + if (!WinsockNetLayer::JoinGame(hostIP, hostPort)) + { + app.DebugPrintf("Win64 LAN: Failed to connect to %s:%d\n", hostIP, hostPort); + return CGameNetworkManager::JOINGAME_FAIL_GENERAL; + } + + BYTE localSmallId = WinsockNetLayer::GetLocalSmallId(); + + IQNet::m_player[localSmallId].m_smallId = localSmallId; + IQNet::m_player[localSmallId].m_isRemote = false; + IQNet::m_player[localSmallId].m_isHostPlayer = false; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + wcscpy_s(IQNet::m_player[localSmallId].m_gamertag, 32, pMinecraft->user->name.c_str()); + IQNet::s_playerCount = localSmallId + 1; + + NotifyPlayerJoined(&IQNet::m_player[0]); + NotifyPlayerJoined(&IQNet::m_player[localSmallId]); + + m_pGameNetworkManager->StateChange_AnyToStarting(); + + return CGameNetworkManager::JOINGAME_SUCCESS; +#else + return CGameNetworkManager::JOINGAME_SUCCESS; +#endif +} + +bool CPlatformNetworkManagerStub::SetLocalGame(bool isLocal) +{ + m_bIsOfflineGame = isLocal; + + return true; +} + +void CPlatformNetworkManagerStub::SetPrivateGame(bool isPrivate) +{ + app.DebugPrintf("Setting as private game: %s\n", isPrivate ? "yes" : "no" ); + m_bIsPrivateGame = isPrivate; +} + +void CPlatformNetworkManagerStub::RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) +{ + playerChangedCallback[iPad] = callback; + playerChangedCallbackParam[iPad] = callbackParam; +} + +void CPlatformNetworkManagerStub::UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam) +{ + if(playerChangedCallbackParam[iPad] == callbackParam) + { + playerChangedCallback[iPad] = NULL; + playerChangedCallbackParam[iPad] = NULL; + } +} + +void CPlatformNetworkManagerStub::HandleSignInChange() +{ + return; +} + +bool CPlatformNetworkManagerStub::_RunNetworkGame() +{ +#ifdef _WINDOWS64 + extern QNET_STATE _iQNetStubState; + _iQNetStubState = QNET_STATE_GAME_PLAY; + + for (DWORD i = 0; i < IQNet::s_playerCount; i++) + { + if (IQNet::m_player[i].m_isRemote) + { + INetworkPlayer *pNetworkPlayer = getNetworkPlayer(&IQNet::m_player[i]); + if (pNetworkPlayer != NULL && pNetworkPlayer->GetSocket() != NULL) + { + Socket::addIncomingSocket(pNetworkPlayer->GetSocket()); + } + } + } +#endif + return true; +} + +void CPlatformNetworkManagerStub::UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving /*= NULL*/) +{ +// DWORD playerCount = m_pIQNet->GetPlayerCount(); +// +// if( this->m_bLeavingGame ) +// return; +// +// if( GetHostPlayer() == NULL ) +// return; +// +// for(unsigned int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; ++i) +// { +// if( i < playerCount ) +// { +// INetworkPlayer *pNetworkPlayer = GetPlayerByIndex(i); +// +// // We can call this from NotifyPlayerLeaving but at that point the player is still considered in the session +// if( pNetworkPlayer != pNetworkPlayerLeaving ) +// { +// m_hostGameSessionData.players[i] = ((NetworkPlayerXbox *)pNetworkPlayer)->GetUID(); +// +// char *temp; +// temp = (char *)wstringtofilename( pNetworkPlayer->GetOnlineName() ); +// memcpy(m_hostGameSessionData.szPlayers[i],temp,XUSER_NAME_SIZE); +// } +// else +// { +// m_hostGameSessionData.players[i] = NULL; +// memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE); +// } +// } +// else +// { +// m_hostGameSessionData.players[i] = NULL; +// memset(m_hostGameSessionData.szPlayers[i],0,XUSER_NAME_SIZE); +// } +// } +// +// m_hostGameSessionData.hostPlayerUID = ((NetworkPlayerXbox *)GetHostPlayer())->GetQNetPlayer()->GetXuid(); +// m_hostGameSessionData.m_uiGameHostSettings = app.GetGameHostOption(eGameHostOption_All); +} + +int CPlatformNetworkManagerStub::RemovePlayerOnSocketClosedThreadProc( void* lpParam ) +{ + INetworkPlayer *pNetworkPlayer = (INetworkPlayer *)lpParam; + + Socket *socket = pNetworkPlayer->GetSocket(); + + if( socket != NULL ) + { + //printf("Waiting for socket closed event\n"); + socket->m_socketClosedEvent->WaitForSignal(INFINITE); + + //printf("Socket closed event has fired\n"); + // 4J Stu - Clear our reference to this socket + pNetworkPlayer->SetSocket( NULL ); + delete socket; + } + + return g_pPlatformNetworkManager->RemoveLocalPlayer( pNetworkPlayer ); +} + +bool CPlatformNetworkManagerStub::RemoveLocalPlayer( INetworkPlayer *pNetworkPlayer ) +{ + return true; +} + +CPlatformNetworkManagerStub::PlayerFlags::PlayerFlags(INetworkPlayer *pNetworkPlayer, unsigned int count) +{ + // 4J Stu - Don't assert, just make it a multiple of 8! This count is calculated from a load of separate values, + // and makes tweaking world/render sizes a pain if we hit an assert here + count = (count + 8 - 1) & ~(8 - 1); + //assert( ( count % 8 ) == 0 ); + this->m_pNetworkPlayer = pNetworkPlayer; + this->flags = new unsigned char [ count / 8 ]; + memset( this->flags, 0, count / 8 ); + this->count = count; +} +CPlatformNetworkManagerStub::PlayerFlags::~PlayerFlags() +{ + delete [] flags; +} + +// Add a player to the per system flag storage - if we've already got a player from that system, copy its flags over +void CPlatformNetworkManagerStub::SystemFlagAddPlayer(INetworkPlayer *pNetworkPlayer) +{ + PlayerFlags *newPlayerFlags = new PlayerFlags( pNetworkPlayer, m_flagIndexSize); + // If any of our existing players are on the same system, then copy over flags from that one + for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) + { + if( pNetworkPlayer->IsSameSystem(m_playerFlags[i]->m_pNetworkPlayer) ) + { + memcpy( newPlayerFlags->flags, m_playerFlags[i]->flags, m_playerFlags[i]->count / 8 ); + break; + } + } + m_playerFlags.push_back(newPlayerFlags); +} + +// Remove a player from the per system flag storage - just maintains the m_playerFlags vector without any gaps in it +void CPlatformNetworkManagerStub::SystemFlagRemovePlayer(INetworkPlayer *pNetworkPlayer) +{ + for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) + { + if( m_playerFlags[i]->m_pNetworkPlayer == pNetworkPlayer ) + { + delete m_playerFlags[i]; + m_playerFlags[i] = m_playerFlags.back(); + m_playerFlags.pop_back(); + return; + } + } +} + +void CPlatformNetworkManagerStub::SystemFlagReset() +{ + for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) + { + delete m_playerFlags[i]; + } + m_playerFlags.clear(); +} + +// Set a per system flag - this is done by setting the flag on every player that shares that system +void CPlatformNetworkManagerStub::SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index) +{ + if( ( index < 0 ) || ( index >= m_flagIndexSize ) ) return; + if( pNetworkPlayer == NULL ) return; + + for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) + { + if( pNetworkPlayer->IsSameSystem(m_playerFlags[i]->m_pNetworkPlayer) ) + { + m_playerFlags[i]->flags[ index / 8 ] |= ( 128 >> ( index % 8 ) ); + } + } +} + +// Get value of a per system flag - can be read from the flags of the passed in player as anything else sent to that +// system should also have been duplicated here +bool CPlatformNetworkManagerStub::SystemFlagGet(INetworkPlayer *pNetworkPlayer, int index) +{ + if( ( index < 0 ) || ( index >= m_flagIndexSize ) ) return false; + if( pNetworkPlayer == NULL ) + { + return false; + } + + for( unsigned int i = 0; i < m_playerFlags.size(); i++ ) + { + if( m_playerFlags[i]->m_pNetworkPlayer == pNetworkPlayer ) + { + return ( ( m_playerFlags[i]->flags[ index / 8 ] & ( 128 >> ( index % 8 ) ) ) != 0 ); + } + } + return false; +} + +wstring CPlatformNetworkManagerStub::GatherStats() +{ + return L""; +} + +wstring CPlatformNetworkManagerStub::GatherRTTStats() +{ + wstring stats(L"Rtt: "); + + wchar_t stat[32]; + + for(unsigned int i = 0; i < GetPlayerCount(); ++i) + { + IQNetPlayer *pQNetPlayer = ((NetworkPlayerXbox *)GetPlayerByIndex( i ))->GetQNetPlayer(); + + if(!pQNetPlayer->IsLocal()) + { + ZeroMemory(stat,32*sizeof(WCHAR)); + swprintf(stat, 32, L"%d: %d/", i, pQNetPlayer->GetCurrentRtt() ); + stats.append(stat); + } + } + return stats; +} + +void CPlatformNetworkManagerStub::TickSearch() +{ +#ifdef _WINDOWS64 + if (m_SessionsUpdatedCallback == NULL) + return; + + static DWORD lastSearchTime = 0; + DWORD now = GetTickCount(); + if (now - lastSearchTime < 2000) + return; + lastSearchTime = now; + + SearchForGames(); +#endif +} + +void CPlatformNetworkManagerStub::SearchForGames() +{ +#ifdef _WINDOWS64 + std::vector lanSessions = WinsockNetLayer::GetDiscoveredSessions(); + + for (size_t i = 0; i < friendsSessions[0].size(); i++) + delete friendsSessions[0][i]; + friendsSessions[0].clear(); + + for (size_t i = 0; i < lanSessions.size(); i++) + { + FriendSessionInfo *info = new FriendSessionInfo(); + size_t nameLen = wcslen(lanSessions[i].hostName); + info->displayLabel = new wchar_t[nameLen + 1]; + wcscpy_s(info->displayLabel, nameLen + 1, lanSessions[i].hostName); + info->displayLabelLength = (unsigned char)nameLen; + info->displayLabelViewableStartIndex = 0; + + info->data.netVersion = lanSessions[i].netVersion; + info->data.m_uiGameHostSettings = lanSessions[i].gameHostSettings; + info->data.texturePackParentId = lanSessions[i].texturePackParentId; + info->data.subTexturePackId = lanSessions[i].subTexturePackId; + info->data.isReadyToJoin = lanSessions[i].isJoinable; + info->data.isJoinable = lanSessions[i].isJoinable; + strncpy_s(info->data.hostIP, sizeof(info->data.hostIP), lanSessions[i].hostIP, _TRUNCATE); + info->data.hostPort = lanSessions[i].hostPort; + wcsncpy_s(info->data.hostName, XUSER_NAME_SIZE, lanSessions[i].hostName, _TRUNCATE); + info->data.playerCount = lanSessions[i].playerCount; + info->data.maxPlayers = lanSessions[i].maxPlayers; + + info->sessionId = (SessionID)((unsigned __int64)inet_addr(lanSessions[i].hostIP) | ((unsigned __int64)lanSessions[i].hostPort << 32)); + + friendsSessions[0].push_back(info); + } + + m_searchResultsCount[0] = (int)friendsSessions[0].size(); + + if (m_SessionsUpdatedCallback != NULL) + m_SessionsUpdatedCallback(m_pSearchParam); +#endif +} + +int CPlatformNetworkManagerStub::SearchForGamesThreadProc( void* lpParameter ) +{ + return 0; +} + +void CPlatformNetworkManagerStub::SetSearchResultsReady(int resultCount) +{ + m_bSearchResultsReady = true; + m_searchResultsCount[m_lastSearchPad] = resultCount; +} + +vector *CPlatformNetworkManagerStub::GetSessionList(int iPad, int localPlayers, bool partyOnly) +{ + vector *filteredList = new vector(); + for (size_t i = 0; i < friendsSessions[0].size(); i++) + filteredList->push_back(friendsSessions[0][i]); + return filteredList; +} + +bool CPlatformNetworkManagerStub::GetGameSessionInfo(int iPad, SessionID sessionId, FriendSessionInfo *foundSessionInfo) +{ + return false; +} + +void CPlatformNetworkManagerStub::SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam ) +{ + m_SessionsUpdatedCallback = SessionsUpdatedCallback; m_pSearchParam = pSearchParam; +} + +void CPlatformNetworkManagerStub::GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ) +{ + FriendSessionUpdatedFn(true, pParam); +} + +void CPlatformNetworkManagerStub::ForceFriendsSessionRefresh() +{ + app.DebugPrintf("Resetting friends session search data\n"); + + for(unsigned int i = 0; i < XUSER_MAX_COUNT; ++i) + { + m_searchResultsCount[i] = 0; + m_lastSearchStartTime[i] = 0; + delete m_pSearchResults[i]; + m_pSearchResults[i] = NULL; + } +} + +INetworkPlayer *CPlatformNetworkManagerStub::addNetworkPlayer(IQNetPlayer *pQNetPlayer) +{ + NetworkPlayerXbox *pNetworkPlayer = new NetworkPlayerXbox(pQNetPlayer); + pQNetPlayer->SetCustomDataValue((ULONG_PTR)pNetworkPlayer); + currentNetworkPlayers.push_back( pNetworkPlayer ); + return pNetworkPlayer; +} + +void CPlatformNetworkManagerStub::removeNetworkPlayer(IQNetPlayer *pQNetPlayer) +{ + INetworkPlayer *pNetworkPlayer = getNetworkPlayer(pQNetPlayer); + for( AUTO_VAR(it, currentNetworkPlayers.begin()); it != currentNetworkPlayers.end(); it++ ) + { + if( *it == pNetworkPlayer ) + { + currentNetworkPlayers.erase(it); + return; + } + } +} + +INetworkPlayer *CPlatformNetworkManagerStub::getNetworkPlayer(IQNetPlayer *pQNetPlayer) +{ + return pQNetPlayer ? (INetworkPlayer *)(pQNetPlayer->GetCustomDataValue()) : NULL; +} + + +INetworkPlayer *CPlatformNetworkManagerStub::GetLocalPlayerByUserIndex(int userIndex ) +{ + return getNetworkPlayer(m_pIQNet->GetLocalPlayerByUserIndex(userIndex)); +} + +INetworkPlayer *CPlatformNetworkManagerStub::GetPlayerByIndex(int playerIndex) +{ + return getNetworkPlayer(m_pIQNet->GetPlayerByIndex(playerIndex)); +} + +INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerByXuid(PlayerUID xuid) +{ + return getNetworkPlayer( m_pIQNet->GetPlayerByXuid(xuid)) ; +} + +INetworkPlayer * CPlatformNetworkManagerStub::GetPlayerBySmallId(unsigned char smallId) +{ + return getNetworkPlayer(m_pIQNet->GetPlayerBySmallId(smallId)); +} + +INetworkPlayer *CPlatformNetworkManagerStub::GetHostPlayer() +{ + return getNetworkPlayer(m_pIQNet->GetHostPlayer()); +} + +bool CPlatformNetworkManagerStub::IsHost() +{ + return m_pIQNet->IsHost() && !m_bHostChanged; +} + +bool CPlatformNetworkManagerStub::JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo) +{ + return ( m_pIQNet->JoinGameFromInviteInfo( userIndex, userMask, pInviteInfo ) == S_OK); +} + +void CPlatformNetworkManagerStub::SetSessionTexturePackParentId( int id ) +{ + m_hostGameSessionData.texturePackParentId = id; +} + +void CPlatformNetworkManagerStub::SetSessionSubTexturePackId( int id ) +{ + m_hostGameSessionData.subTexturePackId = id; +} + +void CPlatformNetworkManagerStub::Notify(int ID, ULONG_PTR Param) +{ +} + +bool CPlatformNetworkManagerStub::IsInSession() +{ + return m_pIQNet->GetState() != QNET_STATE_IDLE; +} + +bool CPlatformNetworkManagerStub::IsInGameplay() +{ + return m_pIQNet->GetState() == QNET_STATE_GAME_PLAY; +} + +bool CPlatformNetworkManagerStub::IsReadyToPlayOrIdle() +{ + return true; +} diff --git a/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h new file mode 100644 index 0000000..919efd7 --- /dev/null +++ b/Minecraft.Client/Common/Network/PlatformNetworkManagerStub.h @@ -0,0 +1,171 @@ +#pragma once +using namespace std; +#include +#include "..\..\..\Minecraft.World\C4JThread.h" +#include "NetworkPlayerInterface.h" +#include "PlatformNetworkManagerInterface.h" +#include "SessionInfo.h" + +class CPlatformNetworkManagerStub : public CPlatformNetworkManager +{ + friend class CGameNetworkManager; +public: + virtual bool Initialise(CGameNetworkManager *pGameNetworkManager, int flagIndexSize); + virtual void Terminate(); + virtual int GetJoiningReadyPercentage(); + virtual int CorrectErrorIDS(int IDS); + + virtual void DoWork(); + virtual int GetPlayerCount(); + virtual int GetOnlinePlayerCount(); + virtual int GetLocalPlayerMask(int playerIndex); + virtual bool AddLocalPlayerByUserIndex( int userIndex ); + virtual bool RemoveLocalPlayerByUserIndex( int userIndex ); + virtual INetworkPlayer *GetLocalPlayerByUserIndex( int userIndex ); + virtual INetworkPlayer *GetPlayerByIndex(int playerIndex); + virtual INetworkPlayer * GetPlayerByXuid(PlayerUID xuid); + virtual INetworkPlayer * GetPlayerBySmallId(unsigned char smallId); + virtual bool ShouldMessageForFullSession(); + + virtual INetworkPlayer *GetHostPlayer(); + virtual bool IsHost(); + virtual bool JoinGameFromInviteInfo( int userIndex, int userMask, const INVITE_INFO *pInviteInfo); + virtual bool LeaveGame(bool bMigrateHost); + + virtual bool IsInSession(); + virtual bool IsInGameplay(); + virtual bool IsReadyToPlayOrIdle(); + virtual bool IsInStatsEnabledSession(); + virtual bool SessionHasSpace(unsigned int spaceRequired = 1); + virtual void SendInviteGUI(int quadrant); + virtual bool IsAddingPlayer(); + + virtual void HostGame(int localUsersMask, bool bOnlineGame, bool bIsPrivate, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0); + virtual int JoinGame(FriendSessionInfo *searchResult, int localUsersMask, int primaryUserIndex ); + virtual bool SetLocalGame(bool isLocal); + virtual bool IsLocalGame() { return m_bIsOfflineGame; } + virtual void SetPrivateGame(bool isPrivate); + virtual bool IsPrivateGame() { return m_bIsPrivateGame; } + virtual bool IsLeavingGame() { return m_bLeavingGame; } + virtual void ResetLeavingGame() { m_bLeavingGame = false; } + + virtual void RegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam); + virtual void UnRegisterPlayerChangedCallback(int iPad, void (*callback)(void *callbackParam, INetworkPlayer *pPlayer, bool leaving), void *callbackParam); + + virtual void HandleSignInChange(); + + virtual bool _RunNetworkGame(); + +private: + bool isSystemPrimaryPlayer(IQNetPlayer *pQNetPlayer); + virtual bool _LeaveGame(bool bMigrateHost, bool bLeaveRoom); + virtual void _HostGame(int dwUsersMask, unsigned char publicSlots = MINECRAFT_NET_MAX_PLAYERS, unsigned char privateSlots = 0); + virtual bool _StartGame(); + + IQNet * m_pIQNet; // pointer to QNet interface + + HANDLE m_notificationListener; + + vector m_machineQNetPrimaryPlayers; // collection of players that we deem to be the main one for that system + + bool m_bLeavingGame; + bool m_bLeaveGameOnTick; + bool m_migrateHostOnLeave; + bool m_bHostChanged; + + bool m_bIsOfflineGame; + bool m_bIsPrivateGame; + int m_flagIndexSize; + + // This is only maintained by the host, and is not valid on client machines + GameSessionData m_hostGameSessionData; + CGameNetworkManager *m_pGameNetworkManager; +public: + virtual void UpdateAndSetGameSessionData(INetworkPlayer *pNetworkPlayerLeaving = NULL); + +private: + // TODO 4J Stu - Do we need to be able to have more than one of these? + void (*playerChangedCallback[XUSER_MAX_COUNT])(void *callbackParam, INetworkPlayer *pPlayer, bool leaving); + void *playerChangedCallbackParam[XUSER_MAX_COUNT]; + + static int RemovePlayerOnSocketClosedThreadProc( void* lpParam ); + virtual bool RemoveLocalPlayer( INetworkPlayer *pNetworkPlayer ); + + // Things for handling per-system flags + class PlayerFlags + { + public: + INetworkPlayer *m_pNetworkPlayer; + unsigned char *flags; + unsigned int count; + PlayerFlags(INetworkPlayer *pNetworkPlayer, unsigned int count); + ~PlayerFlags(); + }; + vector m_playerFlags; + void SystemFlagAddPlayer(INetworkPlayer *pNetworkPlayer); + void SystemFlagRemovePlayer(INetworkPlayer *pNetworkPlayer); + void SystemFlagReset(); +public: + virtual void SystemFlagSet(INetworkPlayer *pNetworkPlayer, int index); + virtual bool SystemFlagGet(INetworkPlayer *pNetworkPlayer, int index); + + // For telemetry +private: + float m_lastPlayerEventTimeStart; + +public: + wstring GatherStats(); + wstring GatherRTTStats(); + +private: + vector friendsSessions[XUSER_MAX_COUNT]; + int m_searchResultsCount[XUSER_MAX_COUNT]; + int m_lastSearchStartTime[XUSER_MAX_COUNT]; + + // The results that will be filled in with the current search + XSESSION_SEARCHRESULT_HEADER *m_pSearchResults[XUSER_MAX_COUNT]; + XNQOS *m_pQoSResult[XUSER_MAX_COUNT]; + + // The results from the previous search, which are currently displayed in the game + XSESSION_SEARCHRESULT_HEADER *m_pCurrentSearchResults[XUSER_MAX_COUNT]; + XNQOS *m_pCurrentQoSResult[XUSER_MAX_COUNT]; + int m_currentSearchResultsCount[XUSER_MAX_COUNT]; + + int m_lastSearchPad; + bool m_bSearchResultsReady; + bool m_bSearchPending; + LPVOID m_pSearchParam; + void (*m_SessionsUpdatedCallback)(LPVOID pParam); + + C4JThread* m_SearchingThread; + + void TickSearch(); + void SearchForGames(); + static int SearchForGamesThreadProc( void* lpParameter ); + + void SetSearchResultsReady(int resultCount = 0); + + vectorcurrentNetworkPlayers; + INetworkPlayer *addNetworkPlayer(IQNetPlayer *pQNetPlayer); + void removeNetworkPlayer(IQNetPlayer *pQNetPlayer); + static INetworkPlayer *getNetworkPlayer(IQNetPlayer *pQNetPlayer); + + virtual void SetSessionTexturePackParentId( int id ); + virtual void SetSessionSubTexturePackId( int id ); + virtual void Notify(int ID, ULONG_PTR Param); + +public: + virtual vector *GetSessionList(int iPad, int localPlayers, bool partyOnly); + virtual bool GetGameSessionInfo(int iPad, SessionID sessionId,FriendSessionInfo *foundSession); + virtual void SetSessionsUpdatedCallback( void (*SessionsUpdatedCallback)(LPVOID pParam), LPVOID pSearchParam ); + virtual void GetFullFriendSessionInfo( FriendSessionInfo *foundSession, void (* FriendSessionUpdatedFn)(bool success, void *pParam), void *pParam ); + virtual void ForceFriendsSessionRefresh(); + +public: + void NotifyPlayerJoined( IQNetPlayer *pQNetPlayer ); + void NotifyPlayerLeaving( IQNetPlayer *pQNetPlayer ); + +#ifndef _XBOX + void FakeLocalPlayerJoined() { NotifyPlayerJoined(m_pIQNet->GetLocalPlayerByUserIndex(0)); } +#endif +}; diff --git a/Minecraft.Client/Common/Network/SessionInfo.h b/Minecraft.Client/Common/Network/SessionInfo.h new file mode 100644 index 0000000..c4b6b9e --- /dev/null +++ b/Minecraft.Client/Common/Network/SessionInfo.h @@ -0,0 +1,127 @@ +#pragma once + +#if defined(__PS3__) || defined(__ORBIS__) +#include "..\..\Common\Network\Sony\SQRNetworkManager.h" +#endif + + +// A struct that we store in the QoS data when we are hosting the session. Max size 1020 bytes. +#ifdef _XBOX +typedef struct _GameSessionData +{ + unsigned short netVersion; // 2 bytes + char hostName[XUSER_NAME_SIZE]; // 16 bytes ( 16*1 ) + GameSessionUID hostPlayerUID; // 8 bytes ( 8*1 ) on xbox, 24 bytes on PS3 + GameSessionUID players[MINECRAFT_NET_MAX_PLAYERS]; // 64 bytes ( 8*8 ) on xbox, 192 ( 24*8) on PS3 + char szPlayers[MINECRAFT_NET_MAX_PLAYERS][XUSER_NAME_SIZE]; // 128 bytes ( 8*16) + unsigned int m_uiGameHostSettings; // 4 bytes + unsigned int texturePackParentId; // 4 bytes + unsigned char subTexturePackId; // 1 byte + + bool isJoinable; // 1 byte + + _GameSessionData() + { + netVersion = 0; + memset(hostName,0,XUSER_NAME_SIZE); + memset(players,0,MINECRAFT_NET_MAX_PLAYERS*sizeof(players[0])); + memset(szPlayers,0,MINECRAFT_NET_MAX_PLAYERS*XUSER_NAME_SIZE); + isJoinable = true; + m_uiGameHostSettings = 0; + texturePackParentId = 0; + subTexturePackId = 0; + } +} GameSessionData; +#elif defined __PS3__ || defined __ORBIS__ || defined(__PSVITA__) +typedef struct _GameSessionData +{ + unsigned short netVersion; // 2 bytes + GameSessionUID hostPlayerUID; // 8 bytes ( 8*1 ) on xbox, 24 bytes on PS3 + GameSessionUID players[MINECRAFT_NET_MAX_PLAYERS]; // 64 bytes ( 8*8 ) on xbox, 192 ( 24*8) on PS3 + unsigned int m_uiGameHostSettings; // 4 bytes + unsigned int texturePackParentId; // 4 bytes + unsigned char subTexturePackId; // 1 byte + + bool isJoinable; // 1 byte + + unsigned char playerCount; // 1 byte + bool isReadyToJoin; // 1 byte + + _GameSessionData() + { + netVersion = 0; + memset(players,0,MINECRAFT_NET_MAX_PLAYERS*sizeof(players[0])); + isJoinable = true; + m_uiGameHostSettings = 0; + texturePackParentId = 0; + subTexturePackId = 0; + playerCount = 0; + isReadyToJoin = false; + + } +} GameSessionData; +#else +typedef struct _GameSessionData +{ + unsigned short netVersion; + unsigned int m_uiGameHostSettings; + unsigned int texturePackParentId; + unsigned char subTexturePackId; + + bool isReadyToJoin; + bool isJoinable; + + char hostIP[64]; + int hostPort; + wchar_t hostName[XUSER_NAME_SIZE]; + unsigned char playerCount; + unsigned char maxPlayers; + + _GameSessionData() + { + netVersion = 0; + m_uiGameHostSettings = 0; + texturePackParentId = 0; + subTexturePackId = 0; + isReadyToJoin = false; + isJoinable = true; + memset(hostIP, 0, sizeof(hostIP)); + hostPort = 0; + memset(hostName, 0, sizeof(hostName)); + playerCount = 0; + maxPlayers = MINECRAFT_NET_MAX_PLAYERS; + } +} GameSessionData; +#endif + +class FriendSessionInfo +{ +public: + SessionID sessionId; +#ifdef _XBOX + XSESSION_SEARCHRESULT searchResult; +#elif defined(__PS3__) || defined(__ORBIS__) || defined (__PSVITA__) + SQRNetworkManager::SessionSearchResult searchResult; +#elif defined(_DURANGO) + DQRNetworkManager::SessionSearchResult searchResult; +#endif + wchar_t *displayLabel; + unsigned char displayLabelLength; + unsigned char displayLabelViewableStartIndex; + GameSessionData data; + bool hasPartyMember; + + FriendSessionInfo() + { + displayLabel = NULL; + displayLabelLength = 0; + displayLabelViewableStartIndex = 0; + hasPartyMember = false; + } + + ~FriendSessionInfo() + { + if(displayLabel!=NULL) + delete displayLabel; + } +}; diff --git a/Minecraft.Client/Common/Potion_Macros.h b/Minecraft.Client/Common/Potion_Macros.h new file mode 100644 index 0000000..29f3e03 --- /dev/null +++ b/Minecraft.Client/Common/Potion_Macros.h @@ -0,0 +1,54 @@ +#pragma once + +// 4J-JEV: +// All functional potions need bit-13 set. + +#define MASK_REGENERATION 0x2001 +#define MASK_SPEED 0x2002 +#define MASK_FIRE_RESISTANCE 0x2003 +#define MASK_POISON 0x2004 +#define MASK_INSTANTHEALTH 0x2005 +#define MASK_NIGHTVISION 0x2006 +#define MASK_INVISIBILITY 0x200E +#define MASK_WEAKNESS 0x2008 +#define MASK_STRENGTH 0x2009 +#define MASK_SLOWNESS 0x200A +#define MASK_INSTANTDAMAGE 0x200C + +#define MASK_TYPE_AWKWARD 0x0010 + +#define MASK_SPLASH 0x4000 +#define MASK_BIT13 0x2000 + +#define MASK_LEVEL2 0x0020 +#define MASK_EXTENDED 0x0040 +#define MASK_LEVEL2EXTENDED 0x0060 + +#define MACRO_POTION_IS_REGENERATION(aux) ((aux & 0x200F) == MASK_REGENERATION) +#define MACRO_POTION_IS_SPEED(aux) ((aux & 0x200F) == MASK_SPEED) +#define MACRO_POTION_IS_FIRE_RESISTANCE(aux) ((aux & 0x200F) == MASK_FIRE_RESISTANCE) +#define MACRO_POTION_IS_INSTANTHEALTH(aux) ((aux & 0x200F) == MASK_INSTANTHEALTH) +#define MACRO_POTION_IS_NIGHTVISION(aux) ((aux & 0x200F) == MASK_NIGHTVISION) +#define MACRO_POTION_IS_INVISIBILITY(aux) ((aux & 0x200F) == MASK_INVISIBILITY) +#define MACRO_POTION_IS_WEAKNESS(aux) ((aux & 0x200F) == MASK_WEAKNESS) +#define MACRO_POTION_IS_STRENGTH(aux) ((aux & 0x200F) == MASK_STRENGTH) +#define MACRO_POTION_IS_SLOWNESS(aux) ((aux & 0x200F) == MASK_SLOWNESS) +#define MACRO_POTION_IS_POISON(aux) ((aux & 0x200F) == MASK_POISON) +#define MACRO_POTION_IS_INSTANTDAMAGE(aux) ((aux & 0x200F) == MASK_INSTANTDAMAGE) + +#define MACRO_POTION_IS_SPLASH(aux) ((aux & MASK_SPLASH) == MASK_SPLASH) +#define MACRO_POTION_IS_BOTTLE(aux) ((aux & MASK_SPLASH) == 0) + +#define MACRO_POTION_IS_AKWARD(aux) ((aux & MASK_TYPE_AWKWARD) == MASK_TYPE_AWKWARD) + +#define MACRO_POTION_IS_REGULAR(aux) ((aux & (MASK_LEVEL2EXTENDED)) == 0) +#define MACRO_POTION_IS_LEVEL2(aux) ((aux & (MASK_LEVEL2 )) == MASK_LEVEL2) +#define MACRO_POTION_IS_EXTENDED(aux) ((aux & (MASK_EXTENDED)) == (MASK_EXTENDED)) +#define MACRO_POTION_IS_LEVEL2EXTENDED(aux) ((aux & (MASK_LEVEL2EXTENDED)) == (MASK_LEVEL2EXTENDED)) + + +#define MACRO_MAKEPOTION_AUXVAL(potion_type, potion_strength, potion_effect) (potion_type | potion_strength | potion_effect) + +// The potion brewing creates high aux values with redundant high bits, so use this to bring the aux val into ranges that match our macros +// 4J-JEV: 0x2000 == bit-13; Used to stop netherwart "resetting" functional potions. +#define NORMALISE_POTION_AUXVAL(aux) (aux & (MASK_BIT13 | MASK_SPLASH | 0xFF)) \ No newline at end of file diff --git a/Minecraft.Client/Common/Telemetry/TelemetryManager.cpp b/Minecraft.Client/Common/Telemetry/TelemetryManager.cpp new file mode 100644 index 0000000..4b04b19 --- /dev/null +++ b/Minecraft.Client/Common/Telemetry/TelemetryManager.cpp @@ -0,0 +1,450 @@ +#include "stdafx.h" + +#include "MultiPlayerLocalPlayer.h" + +#include "..\Minecraft.World\LevelSettings.h" +#include "..\Minecraft.World\LevelData.h" +#include "..\Minecraft.World\Level.h" + +#include "TelemetryManager.h" + +#if !defined(_DURANGO) && !defined(_XBOX) + +CTelemetryManager *TelemetryManager = new CTelemetryManager(); + +#endif + +HRESULT CTelemetryManager::Init() +{ + return S_OK; +} + +HRESULT CTelemetryManager::Tick() +{ + return S_OK; +} + +HRESULT CTelemetryManager::Flush() +{ + return S_OK; +} + +bool CTelemetryManager::RecordPlayerSessionStart(int iPad) +{ + return true; +} + +bool CTelemetryManager::RecordPlayerSessionExit(int iPad, int exitStatus) +{ + return true; +} + +bool CTelemetryManager::RecordHeartBeat(int iPad) +{ + return true; +} + +bool CTelemetryManager::RecordLevelStart(int iPad, ESen_FriendOrMatch friendsOrMatch, ESen_CompeteOrCoop competeOrCoop, int difficulty, int numberOfLocalPlayers, int numberOfOnlinePlayers) +{ + if(iPad == ProfileManager.GetPrimaryPad() ) m_bFirstFlush = true; + + ++m_levelInstanceID; + m_fLevelStartTime[iPad] = app.getAppTime(); + + return true; +} + +bool CTelemetryManager::RecordLevelExit(int iPad, ESen_LevelExitStatus levelExitStatus) +{ + return true; +} + +bool CTelemetryManager::RecordLevelSaveOrCheckpoint(int iPad, int saveOrCheckPointID, int saveSizeInBytes) +{ + return true; +} + +bool CTelemetryManager::RecordLevelResume(int iPad, ESen_FriendOrMatch friendsOrMatch, ESen_CompeteOrCoop competeOrCoop, int difficulty, int numberOfLocalPlayers, int numberOfOnlinePlayers, int saveOrCheckPointID) +{ + return true; +} + +bool CTelemetryManager::RecordPauseOrInactive(int iPad) +{ + return true; +} + +bool CTelemetryManager::RecordUnpauseOrActive(int iPad) +{ + return true; +} + +bool CTelemetryManager::RecordMenuShown(int iPad, EUIScene menuID, int optionalMenuSubID) +{ + return true; +} + +bool CTelemetryManager::RecordAchievementUnlocked(int iPad, int achievementID, int achievementGamerscore) +{ + return true; +} + +bool CTelemetryManager::RecordMediaShareUpload(int iPad, ESen_MediaDestination mediaDestination, ESen_MediaType mediaType) +{ + return true; +} + +bool CTelemetryManager::RecordUpsellPresented(int iPad, ESen_UpsellID upsellId, int marketplaceOfferID) +{ + return true; +} + +bool CTelemetryManager::RecordUpsellResponded(int iPad, ESen_UpsellID upsellId, int marketplaceOfferID, ESen_UpsellOutcome upsellOutcome) +{ + return true; +} + +bool CTelemetryManager::RecordPlayerDiedOrFailed(int iPad, int lowResMapX, int lowResMapY, int lowResMapZ, int mapID, int playerWeaponID, int enemyWeaponID, ETelemetryChallenges enemyTypeID) +{ + return true; +} + +bool CTelemetryManager::RecordEnemyKilledOrOvercome(int iPad, int lowResMapX, int lowResMapY, int lowResMapZ, int mapID, int playerWeaponID, int enemyWeaponID, ETelemetryChallenges enemyTypeID) +{ + return true; +} + +bool CTelemetryManager::RecordTexturePackLoaded(int iPad, int texturePackId, bool purchased) +{ + return true; +} + +bool CTelemetryManager::RecordSkinChanged(int iPad, int dwSkinId) +{ + return true; +} + +bool CTelemetryManager::RecordBanLevel(int iPad) +{ + return true; +} + +bool CTelemetryManager::RecordUnBanLevel(int iPad) +{ + return true; +} + + + /////////////////////////////////////////////////////////////////// + // 4J-JEV: FOLLOWING LOGIC TAKEN FROM XBOX 'SentientManager.cpp' // + /////////////////////////////////////////////////////////////////// + + +/* +Number of seconds elapsed since Sentient initialize. +Title needs to track this and report it as a property. +These times will be used to create timelines and understand durations. +This should be tracked independently of saved games (restoring a save should not reset the seconds since initialize) +*/ +INT CTelemetryManager::GetSecondsSinceInitialize() +{ + return (INT)(app.getAppTime() - m_initialiseTime); +} + +/* +An in-game setting that significantly differentiates the play style of the game. +(This should be captured as an integer and correspond to mode specific to the game.) +Teams will have to provide the game mappings that correspond to the integers. +The intent is to allow teams to capture data on the highest level categories of gameplay in their game. +For example, a game mode could be the name of the specific mini game (eg: golf vs darts) or a specific multiplayer mode (eg: hoard vs beast.) ModeID = 0 means undefined or unknown. +The intent is to answer the question "How are players playing your game?" +*/ +INT CTelemetryManager::GetMode(DWORD dwUserId) +{ + INT mode = (INT)eTelem_ModeId_Undefined; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if( pMinecraft->localplayers[dwUserId] != NULL && pMinecraft->localplayers[dwUserId]->level != NULL && pMinecraft->localplayers[dwUserId]->level->getLevelData() != NULL ) + { + GameType *gameType = pMinecraft->localplayers[dwUserId]->level->getLevelData()->getGameType(); + + if (gameType->isSurvival()) + { + mode = (INT)eTelem_ModeId_Survival; + } + else if (gameType->isCreative()) + { + mode = (INT)eTelem_ModeId_Creative; + } + else + { + mode = (INT)eTelem_ModeId_Undefined; + } + } + return mode; +} + +/* +Used when a title has more heirarchy required. +OptionalSubMode ID = 0 means undefined or unknown. +For titles that have sub-modes (Sports/Football). +Mode is always an indicator of "How is the player choosing to play my game?" so these do not have to be consecutive. +LevelIDs and SubLevelIDs can be reused as they will always be paired with a Mode/SubModeID, Mode should be unique - SubMode can be shared between modes. +*/ +INT CTelemetryManager::GetSubMode(DWORD dwUserId) +{ + INT subMode = (INT)eTelem_SubModeId_Undefined; + + if(Minecraft::GetInstance()->isTutorial()) + { + subMode = (INT)eTelem_SubModeId_Tutorial; + } + else + { + subMode = (INT)eTelem_SubModeId_Normal; + } + + return subMode; +} + +/* +This is a more granular view of mode, allowing teams to get a sense of the levels or maps players are playing and providing some insight into how players progress through a game. +Teams will have to provide the game mappings that correspond to the integers. +The intent is that a level is highest level at which modes can be dissected and provides an indication of player progression in a game. +The intent is that level start and ends do not occur more than every 2 minutes or so, otherwise the data reported will be difficult to understand. +Levels are unique only within a given modeID - so you can have a ModeID =1, LevelID =1 and a different ModeID=2, LevelID = 1 indicate two completely different levels. +LevelID = 0 means undefined or unknown. +*/ +INT CTelemetryManager::GetLevelId(DWORD dwUserId) +{ + INT levelId = (INT)eTelem_LevelId_Undefined; + + levelId = (INT)eTelem_LevelId_PlayerGeneratedLevel; + + return levelId; +} + +/* +Used when a title has more heirarchy required. OptionalSubLevel ID = 0 means undefined or unknown. +For titles that have sub-levels. +Level is always an indicator of "How far has the player progressed." so when possible these should be consecutive or at least monotonically increasing. +LevelIDs and SubLevelIDs can be reused as they will always be paired with a Mode/SubModeID +*/ +INT CTelemetryManager::GetSubLevelId(DWORD dwUserId) +{ + INT subLevelId = (INT)eTelem_SubLevelId_Undefined; + + Minecraft *pMinecraft = Minecraft::GetInstance(); + + if(pMinecraft->localplayers[dwUserId] != NULL) + { + switch(pMinecraft->localplayers[dwUserId]->dimension) + { + case 0: + subLevelId = (INT)eTelem_SubLevelId_Overworld; + break; + case -1: + subLevelId = (INT)eTelem_SubLevelId_Nether; + break; + case 1: + subLevelId = (INT)eTelem_SubLevelId_End; + break; + }; + } + + return subLevelId; +} + +/* +Build version of the title, used to track changes in development as well as patches/title updates +Allows developer to separate out stats from different builds +*/ +INT CTelemetryManager::GetTitleBuildId() +{ + return (INT)VER_PRODUCTBUILD; +} + +/* +Generated by the game every time LevelStart or LevelResume is called. +This should be a unique ID (can be sequential) within a session. +Helps differentiate level attempts when a play plays the same mode/level - especially with aggregated stats +*/ +INT CTelemetryManager::GetLevelInstanceID() +{ + return (INT)m_levelInstanceID; +} + +/* +MultiplayerinstanceID is a title-generated value that is the same for all players in the same multiplayer session. +Link up players into a single multiplayer session ID. +*/ +INT CTelemetryManager::GetMultiplayerInstanceID() +{ + return m_multiplayerInstanceID; +} + +INT CTelemetryManager::GenerateMultiplayerInstanceId() +{ +#if defined(_DURANGO) || defined(_XBOX) + FILETIME SystemTimeAsFileTime; + GetSystemTimeAsFileTime( &SystemTimeAsFileTime ); + return *((INT *)&SystemTimeAsFileTime.dwLowDateTime); +#else + return 0; +#endif +} + +void CTelemetryManager::SetMultiplayerInstanceId(INT value) +{ + m_multiplayerInstanceID = value; +} + +/* +Indicates whether the game is being played in single or multiplayer mode and whether multiplayer is being played locally or over live. +How social is your game? How do people play it? +*/ +INT CTelemetryManager::GetSingleOrMultiplayer() +{ + INT singleOrMultiplayer = (INT)eSen_SingleOrMultiplayer_Undefined; + + // Unused + //eSen_SingleOrMultiplayer_Single_Player + //eSen_SingleOrMultiplayer_Multiplayer_Live + + if(app.GetLocalPlayerCount() == 1 && g_NetworkManager.GetOnlinePlayerCount() == 0) + { + singleOrMultiplayer = (INT)eSen_SingleOrMultiplayer_Single_Player; + } + else if(app.GetLocalPlayerCount() > 1 && g_NetworkManager.GetOnlinePlayerCount() == 0) + { + singleOrMultiplayer = (INT)eSen_SingleOrMultiplayer_Multiplayer_Local; + } + else if(app.GetLocalPlayerCount() == 1 && g_NetworkManager.GetOnlinePlayerCount() > 0) + { + singleOrMultiplayer = (INT)eSen_SingleOrMultiplayer_Multiplayer_Live; + } + else if(app.GetLocalPlayerCount() > 1 && g_NetworkManager.GetOnlinePlayerCount() > 0) + { + singleOrMultiplayer = (INT)eSen_SingleOrMultiplayer_Multiplayer_Both_Local_and_Live; + } + + return singleOrMultiplayer; +} + +/* +An in-game setting that differentiates the challenge imposed on the user. +Normalized to a standard 5-point scale. Are players changing the difficulty? +*/ +INT CTelemetryManager::GetDifficultyLevel(INT diff) +{ + INT difficultyLevel = (INT)eSen_DifficultyLevel_Undefined; + + switch(diff) + { + case 0: + difficultyLevel = (INT)eSen_DifficultyLevel_Easiest; + break; + case 1: + difficultyLevel = (INT)eSen_DifficultyLevel_Easier; + break; + case 2: + difficultyLevel = (INT)eSen_DifficultyLevel_Normal; + break; + case 3: + difficultyLevel = (INT)eSen_DifficultyLevel_Harder; + break; + } + + // Unused + //eSen_DifficultyLevel_Hardest = 5, + + return difficultyLevel; +} + +/* +Differentiates trial/demo from full purchased titles +Is this a full title or demo? +*/ +INT CTelemetryManager::GetLicense() +{ + INT license = eSen_License_Undefined; + + if(ProfileManager.IsFullVersion()) + { + license = (INT)eSen_License_Full_Purchased_Title; + } + else + { + license = (INT)eSen_License_Trial_or_Demo; + } + return license; +} + +/* +This is intended to capture whether players played using default control scheme or customized the control scheme. +Are players customizing your controls? +*/ +INT CTelemetryManager::GetDefaultGameControls() +{ + INT defaultGameControls = eSen_DefaultGameControls_Undefined; + + // Unused + //eSen_DefaultGameControls_Custom_controls + + defaultGameControls = eSen_DefaultGameControls_Default_controls; + + return defaultGameControls; +} + +/* +Are players changing default audio settings? +This is intended to capture whether players are playing with or without volume and whether they make changes from the default audio settings. +*/ +INT CTelemetryManager::GetAudioSettings(DWORD dwUserId) +{ + INT audioSettings = (INT)eSen_AudioSettings_Undefined; + + if(dwUserId == ProfileManager.GetPrimaryPad()) + { + BYTE volume = app.GetGameSettings(dwUserId,eGameSetting_SoundFXVolume); + + if(volume == 0) + { + audioSettings = (INT)eSen_AudioSettings_Off; + } + else if(volume == DEFAULT_VOLUME_LEVEL) + { + audioSettings = (INT)eSen_AudioSettings_On_Default; + } + else + { + audioSettings = (INT)eSen_AudioSettings_On_CustomSetting; + } + } + return audioSettings; +} + +/* +Refers to the highest level performance metric for your game. +For example, a performance metric could points earned, race time, total kills, etc. +This is entirely up to you and will help us understand how well the player performed, or how far the player progressed in the level before exiting. +How far did users progress before failing/exiting the level? +*/ +INT CTelemetryManager::GetLevelExitProgressStat1() +{ + // 4J Stu - Unused + return 0; +} + +/* +Refers to the highest level performance metric for your game. +For example, a performance metric could points earned, race time, total kills, etc. +This is entirely up to you and will help us understand how well the player performed, or how far the player progressed in the level before exiting. +How far did users progress before failing/exiting the level? +*/ +INT CTelemetryManager::GetLevelExitProgressStat2() +{ + // 4J Stu - Unused + return 0; +} \ No newline at end of file diff --git a/Minecraft.Client/Common/Telemetry/TelemetryManager.h b/Minecraft.Client/Common/Telemetry/TelemetryManager.h new file mode 100644 index 0000000..40b6c04 --- /dev/null +++ b/Minecraft.Client/Common/Telemetry/TelemetryManager.h @@ -0,0 +1,65 @@ +#pragma once + +#include "..\..\Common\UI\UIEnums.h" + +class CTelemetryManager +{ +public: + virtual HRESULT Init(); + virtual HRESULT Tick(); + virtual HRESULT Flush(); + + virtual bool RecordPlayerSessionStart(int iPad); + virtual bool RecordPlayerSessionExit(int iPad, int exitStatus); + virtual bool RecordHeartBeat(int iPad); + virtual bool RecordLevelStart(int iPad, ESen_FriendOrMatch friendsOrMatch, ESen_CompeteOrCoop competeOrCoop, int difficulty, int numberOfLocalPlayers, int numberOfOnlinePlayers); + virtual bool RecordLevelExit(int iPad, ESen_LevelExitStatus levelExitStatus); + virtual bool RecordLevelSaveOrCheckpoint(int iPad, int saveOrCheckPointID, int saveSizeInBytes); + virtual bool RecordLevelResume(int iPad, ESen_FriendOrMatch friendsOrMatch, ESen_CompeteOrCoop competeOrCoop, int difficulty, int numberOfLocalPlayers, int numberOfOnlinePlayers, int saveOrCheckPointID); + virtual bool RecordPauseOrInactive(int iPad); + virtual bool RecordUnpauseOrActive(int iPad); + virtual bool RecordMenuShown(int iPad, EUIScene menuID, int optionalMenuSubID); + virtual bool RecordAchievementUnlocked(int iPad, int achievementID, int achievementGamerscore); + virtual bool RecordMediaShareUpload(int iPad, ESen_MediaDestination mediaDestination, ESen_MediaType mediaType); + virtual bool RecordUpsellPresented(int iPad, ESen_UpsellID upsellId, int marketplaceOfferID); + virtual bool RecordUpsellResponded(int iPad, ESen_UpsellID upsellId, int marketplaceOfferID, ESen_UpsellOutcome upsellOutcome); + virtual bool RecordPlayerDiedOrFailed(int iPad, int lowResMapX, int lowResMapY, int lowResMapZ, int mapID, int playerWeaponID, int enemyWeaponID, ETelemetryChallenges enemyTypeID); + virtual bool RecordEnemyKilledOrOvercome(int iPad, int lowResMapX, int lowResMapY, int lowResMapZ, int mapID, int playerWeaponID, int enemyWeaponID, ETelemetryChallenges enemyTypeID); + virtual bool RecordTexturePackLoaded(int iPad, int texturePackId, bool purchased); + + virtual bool RecordSkinChanged(int iPad, int dwSkinId); + virtual bool RecordBanLevel(int iPad); + virtual bool RecordUnBanLevel(int iPad); + + virtual int GetMultiplayerInstanceID(); + virtual int GenerateMultiplayerInstanceId(); + virtual void SetMultiplayerInstanceId(int value); + +protected: + float m_initialiseTime; + float m_lastHeartbeat; + bool m_bFirstFlush; + + float m_fLevelStartTime[XUSER_MAX_COUNT]; + + INT m_multiplayerInstanceID; + DWORD m_levelInstanceID; + + // Helper functions to get the various common settings + INT GetSecondsSinceInitialize(); + INT GetMode(DWORD dwUserId); + INT GetSubMode(DWORD dwUserId); + INT GetLevelId(DWORD dwUserId); + INT GetSubLevelId(DWORD dwUserId); + INT GetTitleBuildId(); + INT GetLevelInstanceID(); + INT GetSingleOrMultiplayer(); + INT GetDifficultyLevel(INT diff); + INT GetLicense(); + INT GetDefaultGameControls(); + INT GetAudioSettings(DWORD dwUserId); + INT GetLevelExitProgressStat1(); + INT GetLevelExitProgressStat2(); +}; + +extern CTelemetryManager *TelemetryManager; \ No newline at end of file diff --git a/Minecraft.Client/Common/Trial/TrialLevel.mcs b/Minecraft.Client/Common/Trial/TrialLevel.mcs new file mode 100644 index 0000000000000000000000000000000000000000..99b17387f586a3ce007e07a7202e2a4f0288f828 GIT binary patch literal 3354946 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%0AxMYMxAc0U!mWdQ4 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

FJyVdQ(N{0!9~ulf0_0kaBTlKEK*O0=s>@ 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

;g({w3lt>bRo~qf-IFOhHU=IL)_QxOm@gINj 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 z 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

urbW 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Ϣ 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