From b04061b912ec16c4c9c753f2e475f6e2e9514402 Mon Sep 17 00:00:00 2001 From: Creeperface01 Date: Mon, 30 Oct 2017 05:36:10 +0100 Subject: [PATCH] Update to version 1.2 (#1912) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added tripwire hook, hopper, redstone mechanics saving, various improvements * recipes * its not necessary * Fixed cocoa beans * Fixed growing * blame refactor * Ops * Fixed some player IDs * Fixed chunk loading, getSafeSpawn() * Players shouldn't pass through carpets * remove debug * Some vanilla features (eating, breaking sounds) * add Event for pressureplates * add chest sounds * Fix crash * improvements * update * update * update * add returns to setters, stairs collision * Update to 1.2 (Part 1) * Clean up byte castings in inventory packets * Join crash fixed. Chunks still corrupted (#44) * Some new StartGamePacket fields * Some new packets ModalForm is the coolest one, I think :D * It seems that chunk light should not send * Do not send BlockLight * Do not send blockLight * Do not send light * Packets cleanup and fix * Revert local world breaking changes * Fix corrupted chunks * Bump protocol version to 131 * Some protocol changes * Fix player's no gravity * hm hm hm * Fix being unable to show ModalForms (#49) * new blocks, fixed boat (#48) * Fix stained glass pane (#51) * Small block fix (#53) * New Updates from pmmp (#52) * New Updates from pmmp https://github.com/pmmp/PocketMine-MP/commit/3ad1b1ba7f56d72ebc7db1eec110174090b34c5f * packets * blockentity * invetory * ModalForms API (#54) Create them with player.showFormWindow, and then listen to the result with PlayerFormRespondedEvent * It should return windows id (#55) * Opraven crafting atd.. * Fix #57 - Commands show now (#63) * Fix #57 - Commands show now * Fix build * Fix Interact/BlockPlace/Break Events not being called (#64) * Fix #59 - InteractEvent now working (BlockBreak and BlockPlace still work for me even without changes) * Fix build * Fix wrong values * There was not any error * ops * inventory size * fixed form windows a bit * let's make it protected * Use Gson parsing * crafting fix * ops * fixed update block packet * wtf * some fixes * rewrote transaction packet handling (from PMMP) * Fixed inventory * fixed update block packet! (idk how :D ) * fixed buttons image, formatting * fix example config * fix example config * fix item dropping * some improvements from PMMP * fixed entity IDs * more adventure settings * Merge remote-tracking branch 'remotes/origin/master1.2' into GT1.2 # Conflicts: # src/main/java/cn/nukkit/Player.java # src/main/java/cn/nukkit/inventory/CraftingManager.java # src/main/java/cn/nukkit/inventory/PlayerInventory.java # src/main/java/cn/nukkit/math/Angle.java # src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java # src/main/java/cn/nukkit/utils/Utils.java * Fix Floating Text Particle * still crashes * random fixes and additions from PMMP * Small fix of String.equals in ElementButtonImageData. * Maybe fix Joining server crashed and "Disconnecting from Server" * Oops.. * Improved brewing and added fuel * Ops * Add fuel to spawn nbt * Support PlayerSettings FormWindow * Fix Projectile Items. * Broadcast LevelSoundEventPacket, More sounds! * Add PlayerBlockPickEvent + eating sounds * Fix splash potion type * Better method * Repair BossBar, add old title methods for better compatibility (#19) * Make old plugins working on this Nukkit * Forgot these imports * Who did invent this? * Back to how this should be * Forgot this * add fortune * Fixed sounds, signs, block picking * New DummyBossBar API! And it's compatible with the old API. * Oops... * fixed items with compound tag, added client side anvil support * Client-side enchant support, need add some API * maybe better than nothing * Fixed upload/download updating * Default no cape in a new Skin, fix NPE in PlayerListPacket (NPC). * Fix Crafting, ArgTypes + ProtocolVersion (#24) * Fix NPE * Fix Arg types * Change byte to int type Because byte can handle values from -127 to 127, so we need now something bigger. * Update it for MCPE 1.2.1 * Debug crafting * Revert Debug * Hmm * Ignore check for Crafting * Fix build * Arrrrrgh * Do pr... se mnou * Step forward * Do not check items * Remove items from where they are * Remove this debug * set chunk changed * small changes * Big crafting is still buggy, * add Server settings request event * ops * Fix Nukkit sometimes getting wrong Recipe ID (#28) * Make getResultByOutput working * Ban this from happening * Kind of backup here * Fix * Debug * Hm * Remove it * Add possibility to write books (#29) * Add Book & Quill + WrittenBook Book & Quill and the whole writing of books are TODO * Create ItemBookWritten.java * Better have ItemBookWritten than ItemWrittenBook * More constructors * Add getPages method * Load creative items from json * fix * Fixed client-side item movement handling * EaseCation.net * Careless? Multiple equipItem and call event two times. * Fix AdventureSettings not works! WFT we forgot reset() (put packet ID!!!!!!) * Remove old messageQueue, add player.sendChat() * Changed ArrayList to List * Allow plugins to change players view distance * Fixed stained glass pane * Fixed teleport during process movement * Fixed double chest inventory * Update version * don't pickup items in spectator mode * reverted eating sounds * Support Damage Absorption! * Funny😂, add Player.showXboxProfile * Fixed flowerpot item conversion * Fix some logical error in ElementSlider. * Fix no sound when opening ender chest. * Fix no any sounds when closing an ender chest. * Daily enhancement on form (GUI) system 2017/10/13 * FormWindow interpret: This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 * Don't forget reset() in DataPacket#encode * Change EntityInteractable from extends to interface. * Move EntityVehicle#collidingWith to interface to solve the problem of some custom entities. * AdventureSettingsPacket show broadcast, fix setAllowModifyWorld. * Fix Take Item animation * Fix title upgrade of Dummy boss bar * Use method for entity IDs * Fixed sleeping bugs and optimized the bed's notices. * Restoring the DummyBossBar Entity is visible * use String::isEmpty() * Fixed item sending in in double chest inventory * Add serverId in UnconnectedPong Packet * Added jukebox * Make it public * Full Pong result information: MOTD, Sub MOTD and default gamemode. But... But they do not seem to work... Let it go :D * Fixed PlaySoundPacket, temporarily removed music discs * Strange careless of showXboxProfile * Teleport with pitch. * Support fast equip armor by right click on hand * Improved ClientChainData * Fixed armor equip * The xbox info will be show in the player list. * Fixed some incorrect command messages. * A hack to solve the client-side teleporting bug! (inside into the block) * Init the server sub-motd. * If the player is a spectator, when received InventoryTransferPacket, we need calling events with canceled instead of breaking; * Fix Logging (#45) --- README.md | 6 + .../java/cn/nukkit/AdventureSettings.java | 173 +- src/main/java/cn/nukkit/Player.java | 2633 ++++++------- src/main/java/cn/nukkit/PlayerFood.java | 62 +- src/main/java/cn/nukkit/Server.java | 63 +- src/main/java/cn/nukkit/api/API.java | 184 +- src/main/java/cn/nukkit/block/Block.java | 68 +- src/main/java/cn/nukkit/block/BlockAnvil.java | 6 +- src/main/java/cn/nukkit/block/BlockBed.java | 7 +- src/main/java/cn/nukkit/block/BlockBone.java | 53 + ...Workbench.java => BlockCraftingTable.java} | 8 +- .../cn/nukkit/block/BlockEnchantingTable.java | 2 +- .../java/cn/nukkit/block/BlockEndGateway.java | 1 - .../java/cn/nukkit/block/BlockEndStone.java | 2 +- .../java/cn/nukkit/block/BlockFlowerPot.java | 5 + .../java/cn/nukkit/block/BlockGlassPane.java | 3 +- .../nukkit/block/BlockGlassPaneStained.java | 37 + .../cn/nukkit/block/BlockGlassStained.java | 37 + .../java/cn/nukkit/block/BlockGlowstone.java | 14 +- .../java/cn/nukkit/block/BlockJukebox.java | 78 + src/main/java/cn/nukkit/block/BlockLever.java | 2 +- src/main/java/cn/nukkit/block/BlockMelon.java | 11 +- .../java/cn/nukkit/block/BlockOreCoal.java | 17 +- .../java/cn/nukkit/block/BlockOreDiamond.java | 17 +- .../java/cn/nukkit/block/BlockOreEmerald.java | 17 +- .../java/cn/nukkit/block/BlockOreGold.java | 2 +- .../java/cn/nukkit/block/BlockOreIron.java | 2 +- .../java/cn/nukkit/block/BlockOreLapis.java | 14 + .../java/cn/nukkit/block/BlockOreQuartz.java | 17 +- .../cn/nukkit/block/BlockOreRedstone.java | 10 +- .../java/cn/nukkit/block/BlockPistonBase.java | 30 +- .../java/cn/nukkit/block/BlockPlanks.java | 2 +- .../nukkit/block/BlockPressurePlateBase.java | 19 +- src/main/java/cn/nukkit/block/BlockRail.java | 1 - .../cn/nukkit/block/BlockRailActivator.java | 8 +- .../cn/nukkit/block/BlockRailDetector.java | 2 +- .../cn/nukkit/block/BlockRailPowered.java | 26 +- .../cn/nukkit/block/BlockTripWireHook.java | 8 +- .../cn/nukkit/blockentity/BlockEntity.java | 17 +- .../blockentity/BlockEntityBrewingStand.java | 151 +- .../nukkit/blockentity/BlockEntityChest.java | 8 +- .../blockentity/BlockEntityFurnace.java | 9 +- .../nukkit/blockentity/BlockEntityHopper.java | 2 +- .../blockentity/BlockEntityItemFrame.java | 4 +- .../blockentity/BlockEntityJukebox.java | 70 + .../blockentity/BlockEntityPistonArm.java | 97 +- .../nukkit/blockentity/BlockEntitySign.java | 101 +- .../blockentity/BlockEntitySpawnable.java | 10 + src/main/java/cn/nukkit/command/Command.java | 2 +- .../java/cn/nukkit/command/CommandReader.java | 6 +- .../nukkit/command/data/CommandParameter.java | 8 +- .../nukkit/command/defaults/DeopCommand.java | 4 +- .../command/defaults/DifficultyCommand.java | 2 +- .../command/defaults/EnchantCommand.java | 2 +- .../cn/nukkit/command/defaults/OpCommand.java | 4 +- .../defaults/SetWorldSpawnCommand.java | 2 +- .../command/defaults/SpawnpointCommand.java | 2 +- .../command/defaults/TeleportCommand.java | 4 +- .../nukkit/command/defaults/TitleCommand.java | 10 +- src/main/java/cn/nukkit/entity/Entity.java | 61 +- .../java/cn/nukkit/entity/EntityHuman.java | 13 +- .../cn/nukkit/entity/EntityHumanType.java | 13 +- .../cn/nukkit/entity/EntityInteractable.java | 13 +- .../java/cn/nukkit/entity/EntityLiving.java | 11 +- .../java/cn/nukkit/entity/EntityRideable.java | 9 + src/main/java/cn/nukkit/entity/data/Skin.java | 90 + .../cn/nukkit/entity/item/EntityBoat.java | 27 +- .../cn/nukkit/entity/item/EntityItem.java | 6 + .../cn/nukkit/entity/item/EntityVehicle.java | 3 +- .../entity/weather/EntityLightning.java | 4 +- .../event/block/BlockPistonChangeEvent.java | 33 + .../event/entity/EntityDamageEvent.java | 6 +- .../event/entity/EntityInteractEvent.java | 29 + .../event/entity/EntityVehicleEnterEvent.java | 2 +- .../cn/nukkit/event/inventory/BrewEvent.java | 59 + .../inventory/InventoryTransactionEvent.java | 9 +- .../event/inventory/StartBrewEvent.java | 53 + .../event/player/PlayerBlockPickEvent.java | 40 + .../player/PlayerFormRespondedEvent.java | 49 + .../event/player/PlayerItemHeldEvent.java | 13 +- .../nukkit/event/player/PlayerMoveEvent.java | 20 + .../PlayerServerSettingsRequestEvent.java | 39 + .../player/PlayerSettingsRespondedEvent.java | 55 + .../vehicle/EntityEnterVehicleEvent.java | 32 + .../event/vehicle/EntityExitVehicleEvent.java | 32 + .../event/vehicle/VehicleCreateEvent.java | 19 + .../event/vehicle/VehicleDamageEvent.java | 37 + .../event/vehicle/VehicleDestroyEvent.java | 27 + .../java/cn/nukkit/form/element/Element.java | 5 + .../cn/nukkit/form/element/ElementButton.java | 33 + .../form/element/ElementButtonImageData.java | 32 + .../nukkit/form/element/ElementDropdown.java | 57 + .../cn/nukkit/form/element/ElementInput.java | 47 + .../cn/nukkit/form/element/ElementLabel.java | 19 + .../cn/nukkit/form/element/ElementSlider.java | 67 + .../form/element/ElementStepSlider.java | 57 + .../cn/nukkit/form/element/ElementToggle.java | 33 + .../cn/nukkit/form/response/FormResponse.java | 5 + .../form/response/FormResponseCustom.java | 54 + .../form/response/FormResponseData.java | 21 + .../form/response/FormResponseModal.java | 21 + .../form/response/FormResponseSimple.java | 23 + .../cn/nukkit/form/window/FormWindow.java | 19 + .../nukkit/form/window/FormWindowCustom.java | 155 + .../nukkit/form/window/FormWindowModal.java | 72 + .../nukkit/form/window/FormWindowSimple.java | 79 + .../cn/nukkit/inventory/AnvilInventory.java | 20 +- .../cn/nukkit/inventory/BaseInventory.java | 35 +- .../cn/nukkit/inventory/BaseTransaction.java | 53 - .../cn/nukkit/inventory/BigCraftingGrid.java | 16 + .../cn/nukkit/inventory/BrewingInventory.java | 16 +- .../cn/nukkit/inventory/ChestInventory.java | 3 + .../nukkit/inventory/ContainerInventory.java | 6 +- .../cn/nukkit/inventory/CraftingGrid.java | 62 + .../nukkit/inventory/CraftingInventory.java | 27 - .../cn/nukkit/inventory/CraftingManager.java | 44 +- .../inventory/DoubleChestInventory.java | 13 +- .../cn/nukkit/inventory/EnchantInventory.java | 58 +- .../cn/nukkit/inventory/FurnaceInventory.java | 4 +- .../java/cn/nukkit/inventory/Inventory.java | 24 +- .../cn/nukkit/inventory/InventoryType.java | 7 +- .../inventory/PlayerCursorInventory.java | 58 + .../inventory/PlayerEnderChestInventory.java | 9 +- .../cn/nukkit/inventory/PlayerInventory.java | 177 +- src/main/java/cn/nukkit/inventory/Recipe.java | 4 + .../cn/nukkit/inventory/ShapedRecipe.java | 5 + .../cn/nukkit/inventory/ShapelessRecipe.java | 5 + .../inventory/SimpleTransactionGroup.java | 155 - .../java/cn/nukkit/inventory/Transaction.java | 20 - .../cn/nukkit/inventory/TransactionGroup.java | 26 - .../transaction/InventoryTransaction.java | 26 + .../SimpleInventoryTransaction.java | 252 ++ .../action/CreativeInventoryAction.java | 54 + .../transaction/action/DropItemAction.java | 49 + .../transaction/action/InventoryAction.java | 74 + .../transaction/action/SlotChangeAction.java | 70 + .../transaction/data/ReleaseItemData.java | 15 + .../transaction/data/TransactionData.java | 7 + .../transaction/data/UseItemData.java | 22 + .../transaction/data/UseItemOnEntityData.java | 18 + src/main/java/cn/nukkit/item/Item.java | 808 +--- src/main/java/cn/nukkit/item/ItemArmor.java | 22 + .../java/cn/nukkit/item/ItemBookWritten.java | 71 + src/main/java/cn/nukkit/item/ItemBow.java | 103 + src/main/java/cn/nukkit/item/ItemEgg.java | 12 +- .../java/cn/nukkit/item/ItemEnderPearl.java | 12 +- .../java/cn/nukkit/item/ItemExpBottle.java | 12 +- .../java/cn/nukkit/item/ItemPotionSplash.java | 19 +- src/main/java/cn/nukkit/item/ItemRecord.java | 26 + .../java/cn/nukkit/item/ItemRecord11.java | 26 + .../java/cn/nukkit/item/ItemRecord13.java | 26 + .../java/cn/nukkit/item/ItemRecordBlocks.java | 26 + .../java/cn/nukkit/item/ItemRecordCat.java | 26 + .../java/cn/nukkit/item/ItemRecordChirp.java | 26 + .../java/cn/nukkit/item/ItemRecordFar.java | 26 + .../java/cn/nukkit/item/ItemRecordMall.java | 26 + .../cn/nukkit/item/ItemRecordMellohi.java | 26 + .../java/cn/nukkit/item/ItemRecordStal.java | 26 + .../java/cn/nukkit/item/ItemRecordStrad.java | 26 + .../java/cn/nukkit/item/ItemRecordWait.java | 26 + .../java/cn/nukkit/item/ItemRecordWard.java | 26 + .../java/cn/nukkit/item/ItemSnowball.java | 12 +- .../java/cn/nukkit/item/ProjectileItem.java | 70 + .../nukkit/item/enchantment/Enchantment.java | 2 +- src/main/java/cn/nukkit/level/GameRules.java | 1 + src/main/java/cn/nukkit/level/Level.java | 43 +- .../level/format/anvil/ChunkRequestTask.java | 4 - .../level/format/anvil/ChunkSection.java | 12 +- .../format/generic/EmptyChunkSection.java | 9 +- .../nukkit/level/format/leveldb/LevelDB.java | 4 +- .../level/particle/FloatingTextParticle.java | 31 +- .../level/sound/LevelSoundEventSound.java | 8 +- src/main/java/cn/nukkit/math/Angle.java | 266 +- .../java/cn/nukkit/math/BlockVector3.java | 8 + src/main/java/cn/nukkit/math/NukkitMath.java | 2 +- src/main/java/cn/nukkit/math/Vector3.java | 8 + src/main/java/cn/nukkit/math/Vector3f.java | 8 + src/main/java/cn/nukkit/network/Network.java | 49 +- .../cn/nukkit/network/RakNetInterface.java | 9 +- .../protocol/AddBehaviorTreePacket.java | 22 + .../network/protocol/AddEntityPacket.java | 4 +- .../protocol/AddHangingEntityPacket.java | 39 - .../network/protocol/AddItemEntityPacket.java | 4 +- .../network/protocol/AddItemPacket.java | 25 - .../network/protocol/AddPaintingPacket.java | 6 +- .../network/protocol/AddPlayerPacket.java | 4 +- .../protocol/AdventureSettingsPacket.java | 134 +- .../network/protocol/AnimatePacket.java | 8 +- .../protocol/AvailableCommandsPacket.java | 81 +- .../protocol/BlockEntityDataPacket.java | 4 +- .../network/protocol/BlockEventPacket.java | 2 +- .../protocol/BlockPickRequestPacket.java | 4 +- .../network/protocol/BookEditPacket.java | 19 + .../network/protocol/BossEventPacket.java | 77 +- .../nukkit/network/protocol/CameraPacket.java | 25 + .../protocol/ChangeDimensionPacket.java | 4 +- .../ClientToServerHandshakePacket.java | 19 + .../ClientboundMapItemDataPacket.java | 18 +- .../protocol/CommandBlockUpdatePacket.java | 62 + .../protocol/CommandRequestPacket.java | 45 + .../network/protocol/CommandStepPacket.java | 62 - .../protocol/ContainerClosePacket.java | 6 +- .../network/protocol/ContainerOpenPacket.java | 24 +- .../protocol/ContainerSetContentPacket.java | 79 - .../protocol/ContainerSetDataPacket.java | 14 +- .../protocol/ContainerSetSlotPacket.java | 41 - .../network/protocol/CraftingEventPacket.java | 9 +- .../nukkit/network/protocol/DataPacket.java | 1 + .../network/protocol/DropItemPacket.java | 31 - .../network/protocol/EntityEventPacket.java | 53 +- .../network/protocol/EntityFallPacket.java | 2 +- .../protocol/EntityPickRequestPacket.java | 21 + .../network/protocol/ExplodePacket.java | 2 +- .../protocol/GUIDataPickItemPacket.java | 22 + .../InitiateWebSocketConnectionPacket.java | 19 + .../network/protocol/InteractPacket.java | 18 +- .../protocol/InventoryActionPacket.java | 32 - .../protocol/InventoryContentPacket.java | 60 + .../network/protocol/InventorySlotPacket.java | 35 + .../protocol/InventoryTransactionPacket.java | 144 + .../protocol/ItemFrameDropItemPacket.java | 2 +- .../network/protocol/LevelEventPacket.java | 18 +- .../protocol/LevelSoundEventPacket.java | 285 +- .../nukkit/network/protocol/LoginPacket.java | 17 +- .../protocol/MapInfoRequestPacket.java | 2 +- .../protocol/MobArmorEquipmentPacket.java | 4 +- .../network/protocol/MobEffectPacket.java | 2 +- .../network/protocol/MobEquipmentPacket.java | 16 +- .../protocol/ModalFormRequestPacket.java | 24 + .../protocol/ModalFormResponsePacket.java | 23 + .../network/protocol/MoveEntityPacket.java | 4 +- .../network/protocol/MovePlayerPacket.java | 26 +- .../network/protocol/NPCRequestPacket.java | 19 + .../network/protocol/PlaySoundPacket.java | 3 +- .../network/protocol/PlayerActionPacket.java | 45 +- .../network/protocol/PlayerHotbarPacket.java | 45 + .../network/protocol/PlayerListPacket.java | 14 + .../network/protocol/PlayerSkinPacket.java | 49 + .../nukkit/network/protocol/ProtocolInfo.java | 100 +- .../network/protocol/RemoveBlockPacket.java | 33 - .../network/protocol/RemoveEntityPacket.java | 2 +- .../protocol/ReplaceItemInSlotPacket.java | 30 - .../network/protocol/RiderJumpPacket.java | 3 +- .../protocol/ServerSettingsRequestPacket.java | 19 + .../ServerSettingsResponsePacket.java | 24 + .../ServerToClientHandshakePacket.java | 23 + .../network/protocol/SetEntityDataPacket.java | 2 +- .../network/protocol/SetEntityLinkPacket.java | 7 +- .../protocol/SetEntityMotionPacket.java | 2 +- .../network/protocol/SetLastHurtByPacket.java | 19 + .../protocol/SetSpawnPositionPacket.java | 2 +- .../network/protocol/ShowCreditsPacket.java | 3 +- .../network/protocol/ShowProfilePacket.java | 28 + .../network/protocol/SimpleEventPacket.java | 22 + .../network/protocol/StartGamePacket.java | 27 +- .../network/protocol/StopSoundPacket.java | 1 + .../protocol/StructureBlockUpdatePacket.java | 19 + .../protocol/SubClientLoginPacket.java | 19 + .../protocol/TakeItemEntityPacket.java | 6 +- .../protocol/TelemetryEventPacket.java | 26 + .../nukkit/network/protocol/TextPacket.java | 3 + .../network/protocol/TransferPacket.java | 4 +- .../protocol/UpdateAttributesPacket.java | 2 +- .../network/protocol/UpdateBlockPacket.java | 3 +- .../protocol/UpdateEquipmentPacket.java | 30 + .../network/protocol/UpdateTradePacket.java | 13 +- .../network/protocol/UseItemPacket.java | 64 - .../network/protocol/types/ContainerIds.java | 18 + .../types/NetworkInventoryAction.java | 233 ++ .../cn/nukkit/network/query/QueryHandler.java | 2 +- src/main/java/cn/nukkit/potion/Effect.java | 9 + .../nukkit/raknet/server/SessionManager.java | 2 +- .../resourcepacks/AbstractResourcePack.java | 2 +- .../cn/nukkit/scheduler/NukkitRunnable.java | 10 +- .../cn/nukkit/scheduler/ServerScheduler.java | 18 +- src/main/java/cn/nukkit/utils/Binary.java | 36 +- .../java/cn/nukkit/utils/BinaryStream.java | 98 +- .../java/cn/nukkit/utils/ClientChainData.java | 346 +- .../java/cn/nukkit/utils/ConfigSection.java | 22 +- .../java/cn/nukkit/utils/DummyBossBar.java | 243 ++ .../java/cn/nukkit/utils/LoginChainData.java | 39 + src/main/java/cn/nukkit/utils/MainLogger.java | 2 +- .../java/cn/nukkit/utils/MinecartType.java | 5 +- src/main/java/cn/nukkit/utils/Rail.java | 25 +- src/main/java/cn/nukkit/utils/VarInt.java | 84 +- src/main/java/cn/nukkit/utils/Zlib.java | 7 +- .../utils/completers/CommandsCompleter.java | 11 +- .../utils/completers/PlayersCompleter.java | 11 +- src/main/resources/creativeitems.json | 3352 +++++++++++++++++ .../cn/nukkit/test/ClientChainDataTest.java | 9 +- 290 files changed, 11575 insertions(+), 4566 deletions(-) create mode 100644 src/main/java/cn/nukkit/block/BlockBone.java rename src/main/java/cn/nukkit/block/{BlockWorkbench.java => BlockCraftingTable.java} (81%) create mode 100644 src/main/java/cn/nukkit/block/BlockGlassPaneStained.java create mode 100644 src/main/java/cn/nukkit/block/BlockGlassStained.java create mode 100644 src/main/java/cn/nukkit/block/BlockJukebox.java create mode 100644 src/main/java/cn/nukkit/blockentity/BlockEntityJukebox.java create mode 100644 src/main/java/cn/nukkit/event/block/BlockPistonChangeEvent.java create mode 100644 src/main/java/cn/nukkit/event/entity/EntityInteractEvent.java create mode 100644 src/main/java/cn/nukkit/event/inventory/BrewEvent.java create mode 100644 src/main/java/cn/nukkit/event/inventory/StartBrewEvent.java create mode 100644 src/main/java/cn/nukkit/event/player/PlayerBlockPickEvent.java create mode 100644 src/main/java/cn/nukkit/event/player/PlayerFormRespondedEvent.java create mode 100644 src/main/java/cn/nukkit/event/player/PlayerServerSettingsRequestEvent.java create mode 100644 src/main/java/cn/nukkit/event/player/PlayerSettingsRespondedEvent.java create mode 100644 src/main/java/cn/nukkit/event/vehicle/EntityEnterVehicleEvent.java create mode 100644 src/main/java/cn/nukkit/event/vehicle/EntityExitVehicleEvent.java create mode 100644 src/main/java/cn/nukkit/event/vehicle/VehicleCreateEvent.java create mode 100644 src/main/java/cn/nukkit/event/vehicle/VehicleDamageEvent.java create mode 100644 src/main/java/cn/nukkit/event/vehicle/VehicleDestroyEvent.java create mode 100644 src/main/java/cn/nukkit/form/element/Element.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementButton.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementButtonImageData.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementDropdown.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementInput.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementLabel.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementSlider.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementStepSlider.java create mode 100644 src/main/java/cn/nukkit/form/element/ElementToggle.java create mode 100644 src/main/java/cn/nukkit/form/response/FormResponse.java create mode 100644 src/main/java/cn/nukkit/form/response/FormResponseCustom.java create mode 100644 src/main/java/cn/nukkit/form/response/FormResponseData.java create mode 100644 src/main/java/cn/nukkit/form/response/FormResponseModal.java create mode 100644 src/main/java/cn/nukkit/form/response/FormResponseSimple.java create mode 100644 src/main/java/cn/nukkit/form/window/FormWindow.java create mode 100644 src/main/java/cn/nukkit/form/window/FormWindowCustom.java create mode 100644 src/main/java/cn/nukkit/form/window/FormWindowModal.java create mode 100644 src/main/java/cn/nukkit/form/window/FormWindowSimple.java delete mode 100644 src/main/java/cn/nukkit/inventory/BaseTransaction.java create mode 100644 src/main/java/cn/nukkit/inventory/BigCraftingGrid.java create mode 100644 src/main/java/cn/nukkit/inventory/CraftingGrid.java delete mode 100644 src/main/java/cn/nukkit/inventory/CraftingInventory.java create mode 100644 src/main/java/cn/nukkit/inventory/PlayerCursorInventory.java mode change 100644 => 100755 src/main/java/cn/nukkit/inventory/PlayerEnderChestInventory.java delete mode 100644 src/main/java/cn/nukkit/inventory/SimpleTransactionGroup.java delete mode 100644 src/main/java/cn/nukkit/inventory/Transaction.java delete mode 100644 src/main/java/cn/nukkit/inventory/TransactionGroup.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/InventoryTransaction.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/SimpleInventoryTransaction.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/action/CreativeInventoryAction.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/action/DropItemAction.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/action/InventoryAction.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/action/SlotChangeAction.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/data/ReleaseItemData.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/data/TransactionData.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/data/UseItemData.java create mode 100644 src/main/java/cn/nukkit/inventory/transaction/data/UseItemOnEntityData.java create mode 100644 src/main/java/cn/nukkit/item/ItemBookWritten.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecord.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecord11.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecord13.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordBlocks.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordCat.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordChirp.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordFar.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordMall.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordMellohi.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordStal.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordStrad.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordWait.java create mode 100644 src/main/java/cn/nukkit/item/ItemRecordWard.java create mode 100644 src/main/java/cn/nukkit/item/ProjectileItem.java create mode 100644 src/main/java/cn/nukkit/network/protocol/AddBehaviorTreePacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/AddHangingEntityPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/AddItemPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/BookEditPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/CameraPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ClientToServerHandshakePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/CommandBlockUpdatePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/CommandRequestPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/CommandStepPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/ContainerSetContentPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/ContainerSetSlotPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/DropItemPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/GUIDataPickItemPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/InitiateWebSocketConnectionPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/InventoryActionPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/InventoryContentPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/InventorySlotPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/InventoryTransactionPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ModalFormRequestPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ModalFormResponsePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/NPCRequestPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/PlayerHotbarPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/PlayerSkinPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/RemoveBlockPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/ReplaceItemInSlotPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ServerSettingsRequestPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ServerSettingsResponsePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ServerToClientHandshakePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/SetLastHurtByPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/ShowProfilePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/SimpleEventPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/StructureBlockUpdatePacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/SubClientLoginPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/TelemetryEventPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/UpdateEquipmentPacket.java delete mode 100644 src/main/java/cn/nukkit/network/protocol/UseItemPacket.java create mode 100644 src/main/java/cn/nukkit/network/protocol/types/ContainerIds.java create mode 100644 src/main/java/cn/nukkit/network/protocol/types/NetworkInventoryAction.java create mode 100644 src/main/java/cn/nukkit/utils/DummyBossBar.java create mode 100644 src/main/java/cn/nukkit/utils/LoginChainData.java create mode 100644 src/main/resources/creativeitems.json diff --git a/README.md b/README.md index a2ed31b89e..ee7f80a2e4 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,12 @@ It has a few key advantages over other server software: Nukkit is **under improvement** yet, we welcome contributions. +Example servers running Nukkit +-------------------- +- **play.EaseCation.net** +- **play.GameTeam.cz** +- **MultiLabs.net** + Get Nukkit & Plugins -------------------- diff --git a/src/main/java/cn/nukkit/AdventureSettings.java b/src/main/java/cn/nukkit/AdventureSettings.java index 9b7d35cf76..7b62902ba8 100644 --- a/src/main/java/cn/nukkit/AdventureSettings.java +++ b/src/main/java/cn/nukkit/AdventureSettings.java @@ -2,6 +2,9 @@ import cn.nukkit.network.protocol.AdventureSettingsPacket; +import java.util.EnumMap; +import java.util.Map; + /** * Nukkit Project * Author: MagicDroidX @@ -14,27 +17,12 @@ public class AdventureSettings implements Cloneable { public static final int PERMISSION_AUTOMATION = 3; public static final int PERMISSION_ADMIN = 4; - private boolean canDestroyBlock = true; - - private boolean autoJump = true; - - private boolean canFly = false; - - private boolean flying = false; - - private boolean noclip = false; - - private boolean noPvp = false; - - private boolean noPvm = false; - - private boolean noMvp = false; - - private boolean muted = false; + private Map values = new EnumMap<>(Type.class); private Player player; - private AdventureSettings() { + public AdventureSettings(Player player) { + this.player = player; } public AdventureSettings clone(Player newPlayer) { @@ -47,129 +35,62 @@ public AdventureSettings clone(Player newPlayer) { } } - public void setCanDestroyBlock(boolean canDestroyBlock) { - this.canDestroyBlock = canDestroyBlock; - } - - public void setAutoJump(boolean autoJump) { - this.autoJump = autoJump; - } - - public void setCanFly(boolean canFly) { - this.canFly = canFly; + public AdventureSettings set(Type type, boolean value) { + this.values.put(type, value); + return this; } - public void setFlying(boolean flying) { - this.flying = flying; - } - - public void setNoclip(boolean noclip) { - this.noclip = noclip; - } - - public void setNoPvp(boolean noPvp) { - this.noPvp = noPvp; - } - - public void setNoPvm(boolean noPvm) { - this.noPvm = noPvm; - } - - public void setNoMvp(boolean noMvp) { - this.noMvp = noMvp; - } - - public void setMuted(boolean muted) { - this.muted = muted; - } - - public boolean canDestroyBlock() { - return canDestroyBlock; - } + public boolean get(Type type) { + Boolean value = this.values.get(type); - public boolean isAutoJumpEnabled() { - return autoJump; - } - - public boolean canFly() { - return canFly; - } - - public boolean isFlying() { - return flying; - } - - public boolean isNoclipEnabled() { - return noclip; - } - - public boolean isNoPvp() { - return noPvp; - } - - public boolean isNoPvm() { - return noPvm; - } - - public boolean isNoMvp() { - return noMvp; - } - - public boolean isMuted() { - return muted; + return value == null ? type.getDefaultValue() : value; } public void update() { AdventureSettingsPacket pk = new AdventureSettingsPacket(); - pk.flags = 0; - pk.worldImmutable = !canDestroyBlock; - pk.autoJump = autoJump; - pk.allowFlight = canFly; - pk.noClip = noclip; - pk.isFlying = flying; - pk.noPvp = noPvp; - pk.noPvm = noPvm; - pk.noMvp = noMvp; - pk.muted = muted; - pk.userPermission = (this.player.isOp() ? PERMISSION_OPERATOR : PERMISSION_NORMAL); - player.dataPacket(pk); - - player.resetInAirTicks(); - } - - public static class Builder { - private final AdventureSettings settings = new AdventureSettings(); - - public Builder(Player player) { - if (player == null) { - throw new IllegalArgumentException("Player can not be null."); - } - - settings.player = player; + for (Type t : Type.values()) { + pk.setFlag(t.getId(), get(t)); } - public Builder canFly(boolean can) { - settings.canFly = can; - return this; - } + pk.commandPermission = (player.isOp() ? AdventureSettingsPacket.PERMISSION_OPERATOR : AdventureSettingsPacket.PERMISSION_NORMAL); + pk.playerPermission = (player.isOp() ? Player.PERMISSION_OPERATOR : Player.PERMISSION_MEMBER); + pk.entityUniqueId = player.getId(); - public Builder noclip(boolean noclip) { - settings.noclip = noclip; - return this; - } + Server.broadcastPacket(Server.getInstance().getOnlinePlayers().values(), pk); + + player.resetInAirTicks(); + } - public Builder canDestroyBlock(boolean can) { - settings.canDestroyBlock = can; - return this; + public enum Type { + WORLD_IMMUTABLE(AdventureSettingsPacket.WORLD_IMMUTABLE, false), + AUTO_JUMP(AdventureSettingsPacket.AUTO_JUMP, true), + ALLOW_FLIGHT(AdventureSettingsPacket.ALLOW_FLIGHT, false), + NO_CLIP(AdventureSettingsPacket.NO_CLIP, false), + WORLD_BUILDER(AdventureSettingsPacket.WORLD_BUILDER, true), + FLYING(AdventureSettingsPacket.FLYING, false), + MUTED(AdventureSettingsPacket.MUTED, false), + BUILD_AND_MINE(AdventureSettingsPacket.BUILD_AND_MINE, true), + DOORS_AND_SWITCHED(AdventureSettingsPacket.DOORS_AND_SWITCHES, true), + OPEN_CONTAINERS(AdventureSettingsPacket.OPEN_CONTAINERS, true), + ATTACK_PLAYERS(AdventureSettingsPacket.ATTACK_PLAYERS, true), + ATTACK_MOBS(AdventureSettingsPacket.ATTACK_MOBS, true), + OPERATOR(AdventureSettingsPacket.OPERATOR, false), + TELEPORT(AdventureSettingsPacket.TELEPORT, false); + + private final int id; + private final boolean defaultValue; + + Type(int id, boolean defaultValue) { + this.id = id; + this.defaultValue = defaultValue; } - public Builder autoJump(boolean autoJump) { - settings.autoJump = autoJump; - return this; + public int getId() { + return id; } - public AdventureSettings build() { - return this.settings; + public boolean getDefaultValue() { + return this.defaultValue; } } } diff --git a/src/main/java/cn/nukkit/Player.java b/src/main/java/cn/nukkit/Player.java index f22862ca05..b3a2447859 100644 --- a/src/main/java/cn/nukkit/Player.java +++ b/src/main/java/cn/nukkit/Player.java @@ -1,33 +1,42 @@ package cn.nukkit; +import cn.nukkit.AdventureSettings.Type; import cn.nukkit.block.*; import cn.nukkit.blockentity.BlockEntity; import cn.nukkit.blockentity.BlockEntityItemFrame; -import cn.nukkit.blockentity.BlockEntitySign; import cn.nukkit.blockentity.BlockEntitySpawnable; import cn.nukkit.command.Command; import cn.nukkit.command.CommandSender; import cn.nukkit.command.data.CommandDataVersions; -import cn.nukkit.command.data.CommandParameter; -import cn.nukkit.command.data.args.CommandArg; -import cn.nukkit.command.data.args.CommandArgBlockVector; import cn.nukkit.entity.*; import cn.nukkit.entity.data.*; import cn.nukkit.entity.item.*; -import cn.nukkit.entity.mob.EntityCreeper; -import cn.nukkit.entity.projectile.*; +import cn.nukkit.entity.projectile.EntityArrow; import cn.nukkit.event.block.ItemFrameDropItemEvent; -import cn.nukkit.event.block.SignChangeEvent; -import cn.nukkit.event.entity.*; +import cn.nukkit.event.entity.EntityDamageByBlockEvent; +import cn.nukkit.event.entity.EntityDamageByEntityEvent; +import cn.nukkit.event.entity.EntityDamageEvent; import cn.nukkit.event.entity.EntityDamageEvent.DamageCause; import cn.nukkit.event.entity.EntityDamageEvent.DamageModifier; -import cn.nukkit.event.inventory.*; +import cn.nukkit.event.inventory.CraftItemEvent; +import cn.nukkit.event.inventory.InventoryCloseEvent; +import cn.nukkit.event.inventory.InventoryPickupArrowEvent; +import cn.nukkit.event.inventory.InventoryPickupItemEvent; import cn.nukkit.event.player.*; import cn.nukkit.event.player.PlayerInteractEvent.Action; import cn.nukkit.event.player.PlayerTeleportEvent.TeleportCause; import cn.nukkit.event.server.DataPacketReceiveEvent; import cn.nukkit.event.server.DataPacketSendEvent; +import cn.nukkit.form.window.FormWindow; +import cn.nukkit.form.window.FormWindowCustom; import cn.nukkit.inventory.*; +import cn.nukkit.inventory.transaction.InventoryTransaction; +import cn.nukkit.inventory.transaction.SimpleInventoryTransaction; +import cn.nukkit.inventory.transaction.action.InventoryAction; +import cn.nukkit.inventory.transaction.action.SlotChangeAction; +import cn.nukkit.inventory.transaction.data.ReleaseItemData; +import cn.nukkit.inventory.transaction.data.UseItemData; +import cn.nukkit.inventory.transaction.data.UseItemOnEntityData; import cn.nukkit.item.*; import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.item.food.Food; @@ -43,13 +52,14 @@ import cn.nukkit.level.particle.PunchBlockParticle; import cn.nukkit.level.sound.ExperienceOrbSound; import cn.nukkit.level.sound.ItemFrameItemRemovedSound; -import cn.nukkit.level.sound.LaunchSound; import cn.nukkit.math.*; import cn.nukkit.metadata.MetadataValue; import cn.nukkit.nbt.NBTIO; import cn.nukkit.nbt.tag.*; import cn.nukkit.network.SourceInterface; import cn.nukkit.network.protocol.*; +import cn.nukkit.network.protocol.types.ContainerIds; +import cn.nukkit.network.protocol.types.NetworkInventoryAction; import cn.nukkit.permission.PermissibleBase; import cn.nukkit.permission.Permission; import cn.nukkit.permission.PermissionAttachment; @@ -61,14 +71,14 @@ import cn.nukkit.utils.*; import co.aikar.timings.Timing; import co.aikar.timings.Timings; -import com.google.gson.Gson; -import com.google.gson.JsonElement; +import java.awt.*; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteOrder; import java.util.*; -import java.util.concurrent.ThreadLocalRandom; +import java.util.List; +import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicReference; /** @@ -94,6 +104,14 @@ public class Player extends EntityHuman implements CommandSender, InventoryHolde public static final float DEFAULT_SPEED = 0.1f; public static final float MAXIMUM_SPEED = 0.5f; + public static final int PERMISSION_CUSTOM = 3; + public static final int PERMISSION_OPERATOR = 2; + public static final int PERMISSION_MEMBER = 1; + public static final int PERMISSION_VISITOR = 0; + + public static final int ANVIL_WINDOW_ID = 2; + public static final int ENCHANT_WINDOW_ID = 3; + protected final SourceInterface interfaz; public boolean playedBefore; @@ -102,11 +120,12 @@ public class Player extends EntityHuman implements CommandSender, InventoryHolde public int gamemode; public long lastBreak; - protected int windowCnt = 2; + protected int windowCnt = 4; protected Map windows; protected Map windowIndex = new HashMap<>(); + protected Set permanentWindows = new HashSet<>(); protected int messageCounter = 2; @@ -116,10 +135,11 @@ public class Player extends EntityHuman implements CommandSender, InventoryHolde public final HashSet achievements = new HashSet<>(); - protected SimpleTransactionGroup currentTransaction = null; - public int craftingType = CRAFTING_SMALL; + protected PlayerCursorInventory cursorInventory; + protected CraftingGrid craftingGrid; + public long creationTime = 0; protected long randomClientId; @@ -195,10 +215,38 @@ public class Player extends EntityHuman implements CommandSender, InventoryHolde protected int lastEnderPearl = -1; - private ClientChainData loginChainData; + private LoginChainData loginChainData; + + public Block breakingBlock = null; public int pickedXPOrb = 0; + protected int formWindowCount = 0; + protected Map formWindows = new HashMap<>(); + protected Map serverSettings = new HashMap<>(); + + protected Map dummyBossBars = new HashMap<>(); + + public int getStartActionTick() { + return startAction; + } + + public void startAction() { + this.startAction = this.server.getTick(); + } + + public void stopAction() { + this.startAction = -1; + } + + public int getLastEnderPearlThrowingTick() { + return lastEnderPearl; + } + + public void onThrowEnderPearl() { + this.lastEnderPearl = this.server.getTick(); + } + public BlockEnderChest getViewingEnderChest() { return viewingEnderChest; } @@ -293,24 +341,42 @@ public void resetInAirTicks() { @Deprecated public void setAllowFlight(boolean value) { - this.getAdventureSettings().setCanFly(value); + this.getAdventureSettings().set(Type.ALLOW_FLIGHT, value); this.getAdventureSettings().update(); } @Deprecated public boolean getAllowFlight() { - return this.getAdventureSettings().canFly(); + return this.getAdventureSettings().get(Type.ALLOW_FLIGHT); + } + + public void setAllowModifyWorld(boolean value) { + this.getAdventureSettings().set(Type.WORLD_IMMUTABLE, !value); + this.getAdventureSettings().set(Type.BUILD_AND_MINE, value); + this.getAdventureSettings().set(Type.WORLD_BUILDER, value); + this.getAdventureSettings().update(); + } + + public void setAllowInteract(boolean value) { + setAllowInteract(value, value); + } + + public void setAllowInteract(boolean value, boolean containers) { + this.getAdventureSettings().set(Type.WORLD_IMMUTABLE, !value); + this.getAdventureSettings().set(Type.DOORS_AND_SWITCHED, value); + this.getAdventureSettings().set(Type.OPEN_CONTAINERS, containers); + this.getAdventureSettings().update(); } @Deprecated public void setAutoJump(boolean value) { - this.getAdventureSettings().setAutoJump(value); + this.getAdventureSettings().set(Type.AUTO_JUMP, value); this.getAdventureSettings().update(); } @Deprecated public boolean hasAutoJump() { - return this.getAdventureSettings().isAutoJumpEnabled(); + return this.getAdventureSettings().get(Type.AUTO_JUMP); } @Override @@ -489,7 +555,7 @@ public void sendCommandData() { } if (count > 0) { //TODO: structure checking - pk.commands = new Gson().toJson(data); + pk.commands = data; int identifier = this.dataPacket(pk, true); // We *need* ACK so we can be sure that the client received the packet or not Thread t = new Thread() { public void run() { @@ -501,7 +567,8 @@ public void run() { sendCommandData(); return; } - } catch (InterruptedException e) {} + } catch (InterruptedException e) { + } } }; t.start(); @@ -540,6 +607,13 @@ public Player(SourceInterface interfaz, Long clientID, String ip, int port) { this.creationTime = System.currentTimeMillis(); } + @Override + protected void initEntity() { + super.initEntity(); + + this.addDefaultWindows(); + } + public boolean isPlayer() { return true; } @@ -563,7 +637,7 @@ public String getDisplayName() { public void setDisplayName(String displayName) { this.displayName = displayName; if (this.spawned) { - this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getDisplayName(), this.getSkin()); + this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getDisplayName(), this.getSkin(), this.getLoginChainData().getXUID()); } } @@ -571,7 +645,7 @@ public void setDisplayName(String displayName) { public void setSkin(Skin skin) { super.setSkin(skin); if (this.spawned) { - this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getDisplayName(), skin); + this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getDisplayName(), skin, this.getLoginChainData().getXUID()); } } @@ -595,6 +669,20 @@ public int getInAirTicks() { return this.inAirTicks; } + /** + * Returns whether the player is currently using an item (right-click and hold). + * + * @return bool + */ + public boolean isUsingItem() { + return this.getDataFlag(DATA_FLAGS, DATA_FLAG_ACTION) && this.startAction > -1; + } + + public void setUsingItem(boolean value) { + this.startAction = value ? this.server.getTick() : -1; + this.setDataFlag(DATA_FLAGS, DATA_FLAG_ACTION, value); + } + public String getButtonText() { return this.buttonText; } @@ -748,7 +836,6 @@ protected void sendNextChunk() { protected void doFirstSpawn() { this.spawned = true; - this.server.sendRecipeList(this); this.getAdventureSettings().update(); this.sendPotionEffects(this); @@ -774,9 +861,7 @@ protected void doFirstSpawn() { respawnPacket.z = (float) pos.z; this.dataPacket(respawnPacket); - PlayStatusPacket playStatusPacket = new PlayStatusPacket(); - playStatusPacket.status = PlayStatusPacket.PLAYER_SPAWN; - this.dataPacket(playStatusPacket); + this.sendPlayStatus(PlayStatusPacket.PLAYER_SPAWN); PlayerJoinEvent playerJoinEvent = new PlayerJoinEvent(this, new TranslationContainer(TextFormat.YELLOW + "%multiplayer.player.joined", new String[]{ @@ -792,6 +877,16 @@ protected void doFirstSpawn() { this.noDamageTicks = 60; + this.getServer().sendRecipeList(this); + + if (this.gamemode == Player.SPECTATOR) { + InventoryContentPacket inventoryContentPacket = new InventoryContentPacket(); + inventoryContentPacket.inventoryId = ContainerIds.CREATIVE; + this.dataPacket(inventoryContentPacket); + } else { + inventory.sendCreativeContents(); + } + for (long index : this.usedChunks.keySet()) { int chunkX = Level.getHashX(index); int chunkZ = Level.getHashZ(index); @@ -843,7 +938,6 @@ protected boolean orderChunks() { int centerX = (int) this.x >> 4; int centerZ = (int) this.z >> 4; - int count = 0; for (int x = -this.chunkRadius; x <= this.chunkRadius; x++) { for (int z = -this.chunkRadius; z <= this.chunkRadius; z++) { @@ -854,7 +948,6 @@ protected boolean orderChunks() { long index; if (!(this.usedChunks.containsKey(index = Level.chunkHash(chunkX, chunkZ))) || !this.usedChunks.get(index)) { newOrder.put(index, distance); - count++; } lastChunk.remove(index); } @@ -1061,14 +1154,12 @@ public int getGamemode() { } /** - * * Returns a client-friendly gamemode of the specified real gamemode * This function takes care of handling gamemodes known to MCPE (as of 1.1.0.3, that includes Survival, Creative and Adventure) - * + *

* TODO: remove this when Spectator Mode gets added properly to MCPE - * */ - private static int getClientFriendlyGamemode(int gamemode){ + private static int getClientFriendlyGamemode(int gamemode) { gamemode &= 0x03; if (gamemode == Player.SPECTATOR) { return Player.CREATIVE; @@ -1091,10 +1182,12 @@ public boolean setGamemode(int gamemode, boolean clientSide, AdventureSettings n if (newSettings == null) { newSettings = this.getAdventureSettings().clone(this); - newSettings.setCanDestroyBlock(gamemode != 3); - newSettings.setCanFly((gamemode & 0x01) > 0); - newSettings.setNoclip(gamemode == 0x03); - newSettings.setFlying(gamemode == 0x03); + newSettings.set(Type.WORLD_IMMUTABLE, (gamemode & 0x02) > 0); + newSettings.set(Type.BUILD_AND_MINE, (gamemode & 0x02) <= 0); + newSettings.set(Type.WORLD_BUILDER, (gamemode & 0x02) <= 0); + newSettings.set(Type.ALLOW_FLIGHT, (gamemode & 0x01) > 0); + newSettings.set(Type.NO_CLIP, gamemode == 0x03); + newSettings.set(Type.FLYING, gamemode == 0x03); } PlayerGameModeChangeEvent ev; @@ -1125,22 +1218,20 @@ public boolean setGamemode(int gamemode, boolean clientSide, AdventureSettings n this.setAdventureSettings(ev.getNewAdventureSettings()); if (this.isSpectator()) { - this.getAdventureSettings().setFlying(true); + this.getAdventureSettings().set(Type.FLYING, true); this.teleport(this.temporalVector.setComponents(this.x, this.y + 0.1, this.z)); - ContainerSetContentPacket containerSetContentPacket = new ContainerSetContentPacket(); - containerSetContentPacket.windowid = ContainerSetContentPacket.SPECIAL_CREATIVE; - containerSetContentPacket.eid = this.id; - this.dataPacket(containerSetContentPacket); + InventoryContentPacket inventoryContentPacket = new InventoryContentPacket(); + inventoryContentPacket.inventoryId = InventoryContentPacket.SPECIAL_CREATIVE; + this.dataPacket(inventoryContentPacket); } else { if (this.isSurvival()) { - this.getAdventureSettings().setFlying(false); + this.getAdventureSettings().set(Type.FLYING, false); } - ContainerSetContentPacket containerSetContentPacket = new ContainerSetContentPacket(); - containerSetContentPacket.windowid = ContainerSetContentPacket.SPECIAL_CREATIVE; - containerSetContentPacket.eid = this.id; - containerSetContentPacket.slots = Item.getCreativeItems().stream().toArray(Item[]::new); - this.dataPacket(containerSetContentPacket); + InventoryContentPacket inventoryContentPacket = new InventoryContentPacket(); + inventoryContentPacket.inventoryId = InventoryContentPacket.SPECIAL_CREATIVE; + inventoryContentPacket.slots = Item.getCreativeItems().stream().toArray(Item[]::new); + this.dataPacket(inventoryContentPacket); } this.resetFallDistance(); @@ -1149,6 +1240,7 @@ public boolean setGamemode(int gamemode, boolean clientSide, AdventureSettings n this.inventory.sendContents(this.getViewers().values()); this.inventory.sendHeldItem(this.hasSpawned.values()); + this.inventory.sendCreativeContents(); return true; } @@ -1301,6 +1393,9 @@ protected void processMovement(int tickDiff) { double dz = newPos.z - this.z; this.fastMove(dx, dy, dz); + if (this.newPosition == null) { + return; //maybe solve that in better way + } double diffX = this.x - newPos.x; double diffY = this.y - newPos.y; @@ -1313,7 +1408,7 @@ protected void processMovement(int tickDiff) { if (diffX != 0 || diffY != 0 || diffZ != 0) { if (this.checkMovement && !server.getAllowFlight() && this.isSurvival()) { - // Some say: I cant move my head when riding because the server + // Some say: I cant move my head when riding because the server // blocked my movement if (!this.isSleeping() && this.riding == null) { double diffHorizontalSqr = (diffX * diffX + diffZ * diffZ) / ((double) (tickDiff * tickDiff)); @@ -1537,7 +1632,7 @@ public boolean onUpdate(int currentTick) { this.inAirTicks = 0; this.highestPosition = this.y; } else { - if (!this.isGliding() && !server.getAllowFlight() && !this.getAdventureSettings().canFly() && this.inAirTicks > 10 && !this.isSleeping() && !this.isImmobile()) { + if (!this.isGliding() && !server.getAllowFlight() && !this.getAdventureSettings().get(Type.ALLOW_FLIGHT) && this.inAirTicks > 10 && !this.isSleeping() && !this.isImmobile()) { double expectedVelocity = (-this.getGravity()) / ((double) this.getDrag()) - ((-this.getGravity()) / ((double) this.getDrag())) * Math.exp(-((double) this.getDrag()) * ((double) (this.inAirTicks - this.startAirTicks))); double diff = (this.speed.y - expectedVelocity) * (this.speed.y - expectedVelocity); @@ -1570,21 +1665,17 @@ public boolean onUpdate(int currentTick) { this.checkTeleportPosition(); this.checkInteractNearby(); - // TODO: remove this workaround (broken client MCPE 1.0.0) - if (!messageQueue.isEmpty()) { - TextPacket pk = new TextPacket(); - pk.type = TextPacket.TYPE_RAW; - pk.message = String.join("\n", messageQueue); - this.dataPacket(pk); - messageQueue.clear(); + if (this.spawned && this.dummyBossBars.size() > 0 && currentTick % 100 == 0) { + this.dummyBossBars.values().forEach(DummyBossBar::updateBossEntityPosition); } + return true; } - - public void checkInteractNearby(){ + + public void checkInteractNearby() { int interactDistance = isCreative() ? 5 : 3; - if(canInteract(this, interactDistance)){ - if(getEntityPlayerLookingAt(interactDistance) != null){ + if (canInteract(this, interactDistance)) { + if (getEntityPlayerLookingAt(interactDistance) != null) { EntityInteractable onInteract = getEntityPlayerLookingAt(interactDistance); setButtonText(onInteract.getInteractButtonText()); } else { @@ -1595,7 +1686,7 @@ public void checkInteractNearby(){ } } - /** + /** * Returns the Entity the player is looking at currently * * @param maxDistance the maximum distance to check for entities @@ -1603,7 +1694,7 @@ public void checkInteractNearby(){ */ public EntityInteractable getEntityPlayerLookingAt(int maxDistance) { timing.startTiming(); - + EntityInteractable entity = null; // just a fix because player MAY not be fully initialized @@ -1632,7 +1723,7 @@ public EntityInteractable getEntityPlayerLookingAt(int maxDistance) { return entity; } - + private EntityInteractable getEntityAtPosition(Entity[] nearbyEntities, int x, int y, int z) { for (Entity nearestEntity : nearbyEntities) { if (nearestEntity.getFloorX() == x && nearestEntity.getFloorY() == y && nearestEntity.getFloorZ() == z @@ -1643,8 +1734,6 @@ private EntityInteractable getEntityAtPosition(Entity[] nearbyEntities, int x, i } return null; } - - private ArrayList messageQueue = new ArrayList<>(); public void checkNetwork() { if (!this.isOnline()) { @@ -1744,12 +1833,12 @@ protected void processLogin() { nbt.putInt("playerGameType", this.gamemode); } - this.adventureSettings = new AdventureSettings.Builder(this) - .canDestroyBlock(!isAdventure()) - .autoJump(true) - .canFly(isCreative()) - .noclip(isSpectator()) - .build(); + this.adventureSettings = new AdventureSettings(this) + .set(Type.WORLD_IMMUTABLE, isAdventure()) + .set(Type.WORLD_BUILDER, !isAdventure()) + .set(Type.AUTO_JUMP, true) + .set(Type.ALLOW_FLIGHT, isCreative()) + .set(Type.NO_CLIP, isSpectator()); Level level; if ((level = this.server.getLevelByName(nbt.getString("Level"))) == null || !alive) { @@ -1779,6 +1868,9 @@ protected void processLogin() { this.server.saveOfflinePlayerData(this.username, nbt, true); } + this.sendPlayStatus(PlayStatusPacket.LOGIN_SUCCESS); + this.server.onPlayerLogin(this); + ListTag posList = nbt.getList("Pos", DoubleTag.class); super.init(this.level.getChunk((int) posList.get(0).data >> 4, (int) posList.get(2).data >> 4, true), nbt); @@ -1793,30 +1885,31 @@ protected void processLogin() { float foodSaturationLevel = this.namedTag.getFloat("foodSaturationLevel"); this.foodData = new PlayerFood(this, foodLevel, foodSaturationLevel); + if (this.isSpectator()) this.keepMovement = true; + + this.forceMovement = this.teleportPosition = this.getPosition(); + + ResourcePacksInfoPacket infoPacket = new ResourcePacksInfoPacket(); + infoPacket.resourcePackEntries = this.server.getResourcePackManager().getResourceStack(); + infoPacket.mustAccept = this.server.getForceResources(); + this.dataPacket(infoPacket); + } + + protected void completeLoginSequence() { PlayerLoginEvent ev; this.server.getPluginManager().callEvent(ev = new PlayerLoginEvent(this, "Plugin reason")); if (ev.isCancelled()) { this.close(this.getLeaveMessage(), ev.getKickMessage()); - return; } - this.server.addOnlinePlayer(this); - this.loggedIn = true; - - if (this.isCreative()) { - this.inventory.setHeldItemSlot(0); - } else { - this.inventory.setHeldItemSlot(this.inventory.getHotbarSlotIndex(0)); - } - - if (this.isSpectator()) this.keepMovement = true; - + Level level; if (this.spawnPosition == null && this.namedTag.contains("SpawnLevel") && (level = this.server.getLevelByName(this.namedTag.getString("SpawnLevel"))) != null) { this.spawnPosition = new Position(this.namedTag.getInt("SpawnX"), this.namedTag.getInt("SpawnY"), this.namedTag.getInt("SpawnZ"), level); } Position spawnPosition = this.getSpawn(); + StartGamePacket startGamePacket = new StartGamePacket(); startGamePacket.entityUniqueId = this.id; startGamePacket.entityRuntimeId = this.id; @@ -1827,8 +1920,8 @@ protected void processLogin() { startGamePacket.yaw = (float) this.yaw; startGamePacket.pitch = (float) this.pitch; startGamePacket.seed = -1; - startGamePacket.dimension = (byte) (this.level.getDimension() & 0xff); - startGamePacket.gamemode = getClientFriendlyGamemode(this.gamemode); + startGamePacket.dimension = (byte) (spawnPosition.level.getDimension() & 0xff); + startGamePacket.worldGamemode = getClientFriendlyGamemode(this.gamemode); startGamePacket.difficulty = this.server.getDifficulty(); startGamePacket.spawnX = (int) spawnPosition.x; startGamePacket.spawnY = (int) spawnPosition.y; @@ -1844,9 +1937,9 @@ protected void processLogin() { startGamePacket.generator = 1; //0 old, 1 infinite, 2 flat this.dataPacket(startGamePacket); - SetTimePacket setTimePacket = new SetTimePacket(); - setTimePacket.time = this.level.getTime(); - this.dataPacket(setTimePacket); + this.loggedIn = true; + + spawnPosition.level.sendTime(this); this.setMovementSpeed(DEFAULT_SPEED); this.sendAttributes(); @@ -1868,26 +1961,10 @@ protected void processLogin() { this.setRemoveFormat(false); } - if (this.gamemode == Player.SPECTATOR) { - ContainerSetContentPacket containerSetContentPacket = new ContainerSetContentPacket(); - containerSetContentPacket.windowid = ContainerSetContentPacket.SPECIAL_CREATIVE; - containerSetContentPacket.eid = this.id; - this.dataPacket(containerSetContentPacket); - } else { - ContainerSetContentPacket containerSetContentPacket = new ContainerSetContentPacket(); - containerSetContentPacket.windowid = ContainerSetContentPacket.SPECIAL_CREATIVE; - containerSetContentPacket.eid = this.id; - containerSetContentPacket.slots = Item.getCreativeItems().stream().toArray(Item[]::new); - this.dataPacket(containerSetContentPacket); - } - this.setEnableClientCommand(true); - this.server.sendFullPlayerListData(this); - - this.forceMovement = this.teleportPosition = this.getPosition(); - - this.server.onPlayerLogin(this); + this.server.addOnlinePlayer(this); + this.server.onPlayerCompleteLoginSequence(this); } public void handleDataPacket(DataPacket packet) { @@ -1919,19 +1996,15 @@ public void handleDataPacket(DataPacket packet) { LoginPacket loginPacket = (LoginPacket) packet; String message; - if (loginPacket.getProtocol() != ProtocolInfo.CURRENT_PROTOCOL) { + if (loginPacket.getProtocol() < ProtocolInfo.CURRENT_PROTOCOL) { if (loginPacket.getProtocol() < ProtocolInfo.CURRENT_PROTOCOL) { message = "disconnectionScreen.outdatedClient"; - PlayStatusPacket pk = new PlayStatusPacket(); - pk.status = PlayStatusPacket.LOGIN_FAILED_CLIENT; - this.directDataPacket(pk); + this.sendPlayStatus(PlayStatusPacket.LOGIN_FAILED_CLIENT); } else { message = "disconnectionScreen.outdatedServer"; - PlayStatusPacket pk = new PlayStatusPacket(); - pk.status = PlayStatusPacket.LOGIN_FAILED_SERVER; - this.directDataPacket(pk); + this.sendPlayStatus(PlayStatusPacket.LOGIN_FAILED_SERVER); } this.close("", message, false); break; @@ -1994,15 +2067,7 @@ public void handleDataPacket(DataPacket packet) { break; } - PlayStatusPacket statusPacket = new PlayStatusPacket(); - statusPacket.status = PlayStatusPacket.LOGIN_SUCCESS; - this.dataPacket(statusPacket); - - ResourcePacksInfoPacket infoPacket = new ResourcePacksInfoPacket(); - infoPacket.resourcePackEntries = this.server.getResourcePackManager().getResourceStack(); - infoPacket.mustAccept = this.server.getForceResources(); - this.dataPacket(infoPacket); - + this.processLogin(); break; case ProtocolInfo.RESOURCE_PACK_CLIENT_RESPONSE_PACKET: ResourcePackClientResponsePacket responsePacket = (ResourcePackClientResponsePacket) packet; @@ -2034,7 +2099,7 @@ public void handleDataPacket(DataPacket packet) { this.dataPacket(stackPacket); break; case ResourcePackClientResponsePacket.STATUS_COMPLETED: - this.processLogin(); + this.completeLoginSequence(); break; } break; @@ -2054,11 +2119,11 @@ public void handleDataPacket(DataPacket packet) { this.dataPacket(dataPacket); break; case ProtocolInfo.PLAYER_INPUT_PACKET: - if(!this.isAlive() || !this.spawned){ + if (!this.isAlive() || !this.spawned) { break; } PlayerInputPacket ipk = (PlayerInputPacket) packet; - if(riding instanceof EntityMinecartAbstract){ + if (riding instanceof EntityMinecartAbstract) { ((EntityMinecartEmpty) riding).setCurrentSpeed(ipk.motionY); } break; @@ -2106,16 +2171,16 @@ public void handleDataPacket(DataPacket packet) { case ProtocolInfo.ADVENTURE_SETTINGS_PACKET: //TODO: player abilities, check for other changes AdventureSettingsPacket adventureSettingsPacket = (AdventureSettingsPacket) packet; - if (adventureSettingsPacket.isFlying && !this.getAdventureSettings().canFly()) { + if (adventureSettingsPacket.getFlag(AdventureSettingsPacket.ALLOW_FLIGHT) && !this.getAdventureSettings().get(Type.ALLOW_FLIGHT)) { this.kick(PlayerKickEvent.Reason.FLYING_DISABLED, "Flying is not enabled on this server"); break; } - PlayerToggleFlightEvent playerToggleFlightEvent = new PlayerToggleFlightEvent(this, adventureSettingsPacket.isFlying); + PlayerToggleFlightEvent playerToggleFlightEvent = new PlayerToggleFlightEvent(this, adventureSettingsPacket.getFlag(AdventureSettingsPacket.ALLOW_FLIGHT)); this.server.getPluginManager().callEvent(playerToggleFlightEvent); if (playerToggleFlightEvent.isCancelled()) { this.getAdventureSettings().update(); } else { - this.getAdventureSettings().setFlying(playerToggleFlightEvent.isFlying()); + this.getAdventureSettings().set(Type.FLYING, playerToggleFlightEvent.isFlying()); } break; case ProtocolInfo.MOB_EQUIPMENT_PACKET: @@ -2125,333 +2190,22 @@ public void handleDataPacket(DataPacket packet) { MobEquipmentPacket mobEquipmentPacket = (MobEquipmentPacket) packet; - if (mobEquipmentPacket.slot == 0x28 || mobEquipmentPacket.slot == 0 || mobEquipmentPacket.slot == 255) { - mobEquipmentPacket.slot = -1; - } else { - mobEquipmentPacket.slot -= 9; - } - - Item item; - int slot; - if (this.isCreative()) { - item = mobEquipmentPacket.item; - slot = Item.getCreativeItemIndex(item); - } else { - item = this.inventory.getItem(mobEquipmentPacket.slot); - slot = mobEquipmentPacket.slot; - } - - if (mobEquipmentPacket.slot == -1) { - if (this.isCreative()) { - boolean found = false; - for (int i = 0; i < this.inventory.getHotbarSize(); ++i) { - if (this.inventory.getHotbarSlotIndex(i) == -1) { - this.inventory.setHeldItemIndex(i); - found = true; - break; - } + Item item = this.inventory.getItem(mobEquipmentPacket.hotbarSlot); - } - if (!found) { - this.inventory.sendContents(this); - break; - } - } else { - if (mobEquipmentPacket.selectedSlot >= 0 && mobEquipmentPacket.selectedSlot < 9) { - this.inventory.setHeldItemIndex(mobEquipmentPacket.selectedSlot); - this.inventory.setHeldItemSlot(mobEquipmentPacket.slot); - } else { - this.inventory.sendContents(this); - break; - } - } - } else if (item == null || slot == -1 || !item.deepEquals(mobEquipmentPacket.item)) { + if (!item.equals(mobEquipmentPacket.item)) { + this.server.getLogger().debug("Tried to equip " + mobEquipmentPacket.item + " but have " + item + " in target slot"); this.inventory.sendContents(this); - break; - } else if (this.isCreative()) { - this.inventory.setHeldItemIndex(mobEquipmentPacket.selectedSlot); - this.inventory.setItem(mobEquipmentPacket.selectedSlot, item); - this.inventory.setHeldItemSlot(mobEquipmentPacket.selectedSlot); - } else { - if (mobEquipmentPacket.selectedSlot >= 0 && mobEquipmentPacket.selectedSlot < this.inventory.getHotbarSize()) { - this.inventory.setHeldItemIndex(mobEquipmentPacket.selectedSlot); - this.inventory.setHeldItemSlot(slot); - } else { - this.inventory.sendContents(this); - break; - } + return; } - this.inventory.sendHeldItem(this.hasSpawned.values()); + this.inventory.equipItem(mobEquipmentPacket.hotbarSlot); this.setDataFlag(Player.DATA_FLAGS, Player.DATA_FLAG_ACTION, false); - break; - case ProtocolInfo.USE_ITEM_PACKET: - if (!this.spawned || !this.isAlive()) { - break; - } - - UseItemPacket useItemPacket = (UseItemPacket) packet; - - Vector3 blockVector = new Vector3(useItemPacket.x, useItemPacket.y, useItemPacket.z); - - this.craftingType = CRAFTING_SMALL; - - if (useItemPacket.face >= 0 && useItemPacket.face <= 5) { - BlockFace face = BlockFace.fromIndex(useItemPacket.face); - this.setDataFlag(Player.DATA_FLAGS, Player.DATA_FLAG_ACTION, false); - - if (!this.canInteract(blockVector.add(0.5, 0.5, 0.5), this.isCreative() ? 13 : 7)) { - } else if (this.isCreative()) { - Item i = this.inventory.getItemInHand(); - if (this.level.useItemOn(blockVector, i, face, useItemPacket.fx, useItemPacket.fy, useItemPacket.fz, this, true) != null) { - break; - } - } else if (!this.inventory.getItemInHand().deepEquals(useItemPacket.item)) { - this.inventory.sendHeldItem(this); - } else { - item = this.inventory.getItemInHand(); - Item oldItem = item.clone(); - //TODO: Implement adventure mode checks - if ((item = this.level.useItemOn(blockVector, item, face, useItemPacket.fx, useItemPacket.fy, useItemPacket.fz, this, true)) != null) { - if (!item.deepEquals(oldItem) || item.getCount() != oldItem.getCount()) { - this.inventory.setItemInHand(item); - this.inventory.sendHeldItem(this.hasSpawned.values()); - } - break; - } - } - - this.inventory.sendHeldItem(this); - - if (blockVector.distanceSquared(this) > 10000) { - break; - } - - Block target = this.level.getBlock(blockVector); - Block block = target.getSide(face); - - if (target instanceof BlockDoor) { - BlockDoor door = (BlockDoor) target; - - Block part; - - if ((door.getDamage() & 0x08) > 0) { //up - part = target.down(); - - if (part.getId() == target.getId()) { - target = part; - } - } - } - - this.level.sendBlocks(new Player[]{this}, new Block[]{target, block}, UpdateBlockPacket.FLAG_ALL_PRIORITY); - break; - } else if (useItemPacket.face == -1) { - Vector3 aimPos = new Vector3( - -Math.sin(this.yaw / 180d * Math.PI) * Math.cos(this.pitch / 180d * Math.PI), - -Math.sin(this.pitch / 180d * Math.PI), - Math.cos(this.yaw / 180d * Math.PI) * Math.cos(this.pitch / 180d * Math.PI) - ); - - if (this.isCreative()) { - item = this.inventory.getItemInHand(); - } else if (!this.inventory.getItemInHand().deepEquals(useItemPacket.item)) { - this.inventory.sendHeldItem(this); - break; - } else { - item = this.inventory.getItemInHand(); - } - - PlayerInteractEvent playerInteractEvent = new PlayerInteractEvent(this, item, aimPos, null, Action.RIGHT_CLICK_AIR); - - this.server.getPluginManager().callEvent(playerInteractEvent); - - if (playerInteractEvent.isCancelled()) { - this.inventory.sendHeldItem(this); - break; - } - - if (item.getId() == Item.SNOWBALL) { - CompoundTag nbt = new CompoundTag() - .putList(new ListTag("Pos") - .add(new DoubleTag("", x)) - .add(new DoubleTag("", y + this.getEyeHeight())) - .add(new DoubleTag("", z))) - .putList(new ListTag("Motion") - .add(new DoubleTag("", -Math.sin(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI))) - .add(new DoubleTag("", -Math.sin(pitch / 180 * Math.PI))) - .add(new DoubleTag("", Math.cos(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI)))) - .putList(new ListTag("Rotation") - .add(new FloatTag("", (float) yaw)) - .add(new FloatTag("", (float) pitch))); - - float f = 1.5f; - EntitySnowball snowball = new EntitySnowball(this.chunk, nbt, this); - - snowball.setMotion(snowball.getMotion().multiply(f)); - if (this.isSurvival()) { - item.setCount(item.getCount() - 1); - this.inventory.setItemInHand(item.getCount() > 0 ? item : Item.get(Item.AIR)); - } - if (snowball instanceof EntityProjectile) { - ProjectileLaunchEvent projectileLaunchEvent = new ProjectileLaunchEvent(snowball); - this.server.getPluginManager().callEvent(projectileLaunchEvent); - if (projectileLaunchEvent.isCancelled()) { - snowball.kill(); - } else { - snowball.spawnToAll(); - this.level.addSound(new LaunchSound(this), this.getViewers().values()); - } - } else { - snowball.spawnToAll(); - } - } else if (item.getId() == Item.EGG) { - CompoundTag nbt = new CompoundTag() - .putList(new ListTag("Pos") - .add(new DoubleTag("", x)) - .add(new DoubleTag("", y + this.getEyeHeight())) - .add(new DoubleTag("", z))) - .putList(new ListTag("Motion") - .add(new DoubleTag("", -Math.sin(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI))) - .add(new DoubleTag("", -Math.sin(pitch / 180 * Math.PI))) - .add(new DoubleTag("", Math.cos(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI)))) - .putList(new ListTag("Rotation") - .add(new FloatTag("", (float) yaw)) - .add(new FloatTag("", (float) pitch))); - - float f = 1.5f; - EntityEgg egg = new EntityEgg(this.chunk, nbt, this); - - egg.setMotion(egg.getMotion().multiply(f)); - if (this.isSurvival()) { - item.setCount(item.getCount() - 1); - this.inventory.setItemInHand(item.getCount() > 0 ? item : Item.get(Item.AIR)); - } - if (egg instanceof EntityProjectile) { - ProjectileLaunchEvent projectileLaunchEvent = new ProjectileLaunchEvent(egg); - this.server.getPluginManager().callEvent(projectileLaunchEvent); - if (projectileLaunchEvent.isCancelled()) { - egg.kill(); - } else { - egg.spawnToAll(); - this.level.addSound(new LaunchSound(this), this.getViewers().values()); - } - } else { - egg.spawnToAll(); - } - } else if (item.getId() == Item.ENDER_PEARL && (this.server.getTick() - this.lastEnderPearl) >= 20) { - CompoundTag nbt = new CompoundTag() - .putList(new ListTag("Pos") - .add(new DoubleTag("", x)) - .add(new DoubleTag("", y + this.getEyeHeight())) - .add(new DoubleTag("", z))) - .putList(new ListTag("Motion") - .add(new DoubleTag("", -Math.sin(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI))) - .add(new DoubleTag("", -Math.sin(pitch / 180 * Math.PI))) - .add(new DoubleTag("", Math.cos(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI)))) - .putList(new ListTag("Rotation") - .add(new FloatTag("", (float) yaw)) - .add(new FloatTag("", (float) pitch))); - - float f = 1.5f; - EntityEnderPearl enderPearl = new EntityEnderPearl(this.chunk, nbt, this); - - enderPearl.setMotion(enderPearl.getMotion().multiply(f)); - if (this.isSurvival()) { - item.setCount(item.getCount() - 1); - this.inventory.setItemInHand(item.getCount() > 0 ? item : Item.get(Item.AIR)); - } - if (enderPearl instanceof EntityProjectile) { - ProjectileLaunchEvent projectileLaunchEvent = new ProjectileLaunchEvent(enderPearl); - this.server.getPluginManager().callEvent(projectileLaunchEvent); - if (projectileLaunchEvent.isCancelled()) { - enderPearl.kill(); - } else { - enderPearl.spawnToAll(); - this.level.addSound(new LaunchSound(this), this.getViewers().values()); - } - } else { - enderPearl.spawnToAll(); - } - this.lastEnderPearl = this.server.getTick(); - } else if (item.getId() == Item.EXPERIENCE_BOTTLE) { - CompoundTag nbt = new CompoundTag() - .putList(new ListTag("Pos") - .add(new DoubleTag("", x)) - .add(new DoubleTag("", y + this.getEyeHeight())) - .add(new DoubleTag("", z))) - .putList(new ListTag("Motion") - .add(new DoubleTag("", -Math.sin(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI))) - .add(new DoubleTag("", -Math.sin(pitch / 180 * Math.PI))) - .add(new DoubleTag("", Math.cos(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI)))) - .putList(new ListTag("Rotation") - .add(new FloatTag("", (float) yaw)) - .add(new FloatTag("", (float) pitch))) - .putInt("Potion", item.getDamage()); - double f = 1.5; - Entity bottle = new EntityExpBottle(this.chunk, nbt, this); - bottle.setMotion(bottle.getMotion().multiply(f)); - if (this.isSurvival()) { - item.setCount(item.getCount() - 1); - this.inventory.setItemInHand(item.getCount() > 0 ? item : Item.get(Item.AIR)); - } - if (bottle instanceof EntityProjectile) { - EntityProjectile bottleEntity = (EntityProjectile) bottle; - ProjectileLaunchEvent projectileEv = new ProjectileLaunchEvent(bottleEntity); - this.server.getPluginManager().callEvent(projectileEv); - if (projectileEv.isCancelled()) { - bottle.kill(); - } else { - bottle.spawnToAll(); - this.level.addSound(new LaunchSound(this), this.getViewers().values()); - } - } else { - bottle.spawnToAll(); - } - } else if (item.getId() == Item.SPLASH_POTION) { - CompoundTag nbt = new CompoundTag() - .putList(new ListTag("Pos") - .add(new DoubleTag("", x)) - .add(new DoubleTag("", y + this.getEyeHeight())) - .add(new DoubleTag("", z))) - .putList(new ListTag("Motion") - .add(new DoubleTag("", -Math.sin(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI))) - .add(new DoubleTag("", -Math.sin(pitch / 180 * Math.PI))) - .add(new DoubleTag("", Math.cos(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI)))) - .putList(new ListTag("Rotation") - .add(new FloatTag("", (float) yaw)) - .add(new FloatTag("", (float) pitch))) - .putShort("PotionId", item.getDamage()); - double f = 1.5; - Entity bottle = new EntityPotion(this.chunk, nbt, this); - bottle.setMotion(bottle.getMotion().multiply(f)); - if (this.isSurvival()) { - item.setCount(item.getCount() - 1); - this.inventory.setItemInHand(item.getCount() > 0 ? item : Item.get(Item.AIR)); - } - if (bottle instanceof EntityPotion) { - EntityPotion bottleEntity = (EntityPotion) bottle; - ProjectileLaunchEvent projectileEv = new ProjectileLaunchEvent(bottleEntity); - this.server.getPluginManager().callEvent(projectileEv); - if (projectileEv.isCancelled()) { - bottle.kill(); - } else { - bottle.spawnToAll(); - this.level.addSound(new LaunchSound(this), this.getViewers().values()); - } - } else { - bottle.spawnToAll(); - } - } - this.setDataFlag(Player.DATA_FLAGS, Player.DATA_FLAG_ACTION, true); - this.startAction = this.server.getTick(); - } break; case ProtocolInfo.PLAYER_ACTION_PACKET: PlayerActionPacket playerActionPacket = (PlayerActionPacket) packet; - if (!this.spawned || (!this.isAlive() && playerActionPacket.action != PlayerActionPacket.ACTION_RESPAWN && playerActionPacket.action != PlayerActionPacket.ACTION_DIMENSION_CHANGE)) { + if (!this.spawned || (!this.isAlive() && playerActionPacket.action != PlayerActionPacket.ACTION_RESPAWN && playerActionPacket.action != PlayerActionPacket.ACTION_DIMENSION_CHANGE_REQUEST)) { break; } @@ -2461,7 +2215,7 @@ public void handleDataPacket(DataPacket packet) { switch (playerActionPacket.action) { case PlayerActionPacket.ACTION_START_BREAK: - if (this.lastBreak != Long.MAX_VALUE || pos.distanceSquared(this) > 10000) { + if (this.lastBreak != Long.MAX_VALUE || pos.distanceSquared(this) > 100) { break; } Block target = this.level.getBlock(pos); @@ -2472,7 +2226,7 @@ public void handleDataPacket(DataPacket packet) { break; } if (target.getId() == Block.NOTEBLOCK) { - ((BlockNoteblock)target).emitSound(); + ((BlockNoteblock) target).emitSound(); break; } Block block = target.getSide(face); @@ -2480,131 +2234,45 @@ public void handleDataPacket(DataPacket packet) { this.level.setBlock(block, new BlockAir(), true); break; } - if(!this.isCreative()){ + if (!this.isCreative()) { //improved this to take stuff like swimming, ladders, enchanted tools into account, fix wrong tool break time calculations for bad tools (pmmp/PocketMine-MP#211) //Done by lmlstarqaq double breakTime = Math.ceil(target.getBreakTime(this.inventory.getItemInHand(), this) * 20); if (breakTime > 0) { LevelEventPacket pk = new LevelEventPacket(); pk.evid = LevelEventPacket.EVENT_BLOCK_START_BREAK; - pk.x = (float)pos.x; - pk.y = (float)pos.y; - pk.z = (float)pos.z; - pk.data = (int)(65535 / breakTime); + pk.x = (float) pos.x; + pk.y = (float) pos.y; + pk.z = (float) pos.z; + pk.data = (int) (65535 / breakTime); this.getLevel().addChunkPacket(pos.getFloorX() >> 4, pos.getFloorZ() >> 4, pk); } } + + this.breakingBlock = target; this.lastBreak = System.currentTimeMillis(); break; case PlayerActionPacket.ACTION_ABORT_BREAK: this.lastBreak = Long.MAX_VALUE; - + this.breakingBlock = null; case PlayerActionPacket.ACTION_STOP_BREAK: LevelEventPacket pk = new LevelEventPacket(); pk.evid = LevelEventPacket.EVENT_BLOCK_STOP_BREAK; - pk.x = (float)pos.x; - pk.y = (float)pos.y; - pk.z = (float)pos.z; + pk.x = (float) pos.x; + pk.y = (float) pos.y; + pk.z = (float) pos.z; pk.data = 0; this.getLevel().addChunkPacket(pos.getFloorX() >> 4, pos.getFloorZ() >> 4, pk); + this.breakingBlock = null; break; - - case PlayerActionPacket.ACTION_RELEASE_ITEM: - if (this.startAction > -1 && this.getDataFlag(Player.DATA_FLAGS, Player.DATA_FLAG_ACTION)) { - if (this.inventory.getItemInHand().getId() == Item.BOW) { - - Item bow = this.inventory.getItemInHand(); - ItemArrow itemArrow = new ItemArrow(); - if (this.isSurvival() && !this.inventory.contains(itemArrow)) { - this.inventory.sendContents(this); - break; - } - - double damage = 2; - boolean flame = false; - - if (bow.hasEnchantments()) { - Enchantment bowDamage = bow.getEnchantment(Enchantment.ID_BOW_POWER); - - if (bowDamage != null && bowDamage.getLevel() > 0) { - damage += 0.25 * (bowDamage.getLevel() + 1); - } - - Enchantment flameEnchant = bow.getEnchantment(Enchantment.ID_BOW_FLAME); - flame = flameEnchant != null && flameEnchant.getLevel() > 0; - } - - CompoundTag nbt = new CompoundTag() - .putList(new ListTag("Pos") - .add(new DoubleTag("", x)) - .add(new DoubleTag("", y + this.getEyeHeight())) - .add(new DoubleTag("", z))) - .putList(new ListTag("Motion") - .add(new DoubleTag("", -Math.sin(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI))) - .add(new DoubleTag("", -Math.sin(pitch / 180 * Math.PI))) - .add(new DoubleTag("", Math.cos(yaw / 180 * Math.PI) * Math.cos(pitch / 180 * Math.PI)))) - .putList(new ListTag("Rotation") - .add(new FloatTag("", (yaw > 180 ? 360 : 0) - (float) yaw)) - .add(new FloatTag("", (float) -pitch))) - .putShort("Fire", this.isOnFire() || flame ? 45 * 60 : 0) - .putDouble("damage", damage); - - int diff = (this.server.getTick() - this.startAction); - double p = (double) diff / 20; - - double f = Math.min((p * p + p * 2) / 3, 1) * 2; - EntityShootBowEvent entityShootBowEvent = new EntityShootBowEvent(this, bow, new EntityArrow(this.chunk, nbt, this, f == 2), f); - - if (f < 0.1 || diff < 5) { - entityShootBowEvent.setCancelled(); - } - - this.server.getPluginManager().callEvent(entityShootBowEvent); - if (entityShootBowEvent.isCancelled()) { - entityShootBowEvent.getProjectile().kill(); - this.inventory.sendContents(this); - } else { - entityShootBowEvent.getProjectile().setMotion(entityShootBowEvent.getProjectile().getMotion().multiply(entityShootBowEvent.getForce())); - if (this.isSurvival()) { - Enchantment infinity; - - if (!bow.hasEnchantments() || (infinity = bow.getEnchantment(Enchantment.ID_BOW_INFINITY)) == null || infinity.getLevel() <= 0) - this.inventory.removeItem(itemArrow); - - if (!bow.isUnbreakable()) { - Enchantment durability = bow.getEnchantment(Enchantment.ID_DURABILITY); - if (!(durability != null && durability.getLevel() > 0 && (100 / (durability.getLevel() + 1)) <= new Random().nextInt(100))) { - bow.setDamage(bow.getDamage() + 1); - if (bow.getDamage() >= 385) { - this.inventory.setItemInHand(new ItemBlock(new BlockAir(), 0, 0)); - } else { - this.inventory.setItemInHand(bow); - } - } - } - } - if (entityShootBowEvent.getProjectile() instanceof EntityProjectile) { - ProjectileLaunchEvent projectev = new ProjectileLaunchEvent(entityShootBowEvent.getProjectile()); - this.server.getPluginManager().callEvent(projectev); - if (projectev.isCancelled()) { - entityShootBowEvent.getProjectile().kill(); - } else { - entityShootBowEvent.getProjectile().spawnToAll(); - this.level.addSound(new LaunchSound(this), this.getViewers().values()); - } - } else { - entityShootBowEvent.getProjectile().spawnToAll(); - } - } - } - } - //milk removed here, see the section of food - + case PlayerActionPacket.ACTION_GET_UPDATED_BLOCK: + break; //TODO + case PlayerActionPacket.ACTION_DROP_ITEM: + break; //TODO case PlayerActionPacket.ACTION_STOP_SLEEPING: this.stopSleep(); break; - case PlayerActionPacket.ACTION_RESPAWN: if (!this.spawned || this.isAlive() || !this.isOnline()) { break; @@ -2616,6 +2284,7 @@ public void handleDataPacket(DataPacket packet) { } this.craftingType = CRAFTING_SMALL; + this.resetCraftingGridType(); PlayerRespawnEvent playerRespawnEvent = new PlayerRespawnEvent(this, this.getSpawn()); this.server.getPluginManager().callEvent(playerRespawnEvent); @@ -2653,10 +2322,8 @@ public void handleDataPacket(DataPacket packet) { this.spawnToAll(); this.scheduleUpdate(); break; - case PlayerActionPacket.ACTION_JUMP: break packetswitch; - case PlayerActionPacket.ACTION_START_SPRINT: PlayerToggleSprintEvent playerToggleSprintEvent = new PlayerToggleSprintEvent(this, true); this.server.getPluginManager().callEvent(playerToggleSprintEvent); @@ -2666,7 +2333,6 @@ public void handleDataPacket(DataPacket packet) { this.setSprinting(true); } break packetswitch; - case PlayerActionPacket.ACTION_STOP_SPRINT: playerToggleSprintEvent = new PlayerToggleSprintEvent(this, false); this.server.getPluginManager().callEvent(playerToggleSprintEvent); @@ -2676,7 +2342,6 @@ public void handleDataPacket(DataPacket packet) { this.setSprinting(false); } break packetswitch; - case PlayerActionPacket.ACTION_START_SNEAK: PlayerToggleSneakEvent playerToggleSneakEvent = new PlayerToggleSneakEvent(this, true); this.server.getPluginManager().callEvent(playerToggleSneakEvent); @@ -2686,7 +2351,6 @@ public void handleDataPacket(DataPacket packet) { this.setSneaking(true); } break packetswitch; - case PlayerActionPacket.ACTION_STOP_SNEAK: playerToggleSneakEvent = new PlayerToggleSneakEvent(this, false); this.server.getPluginManager().callEvent(playerToggleSneakEvent); @@ -2696,7 +2360,8 @@ public void handleDataPacket(DataPacket packet) { this.setSneaking(false); } break packetswitch; - + case PlayerActionPacket.ACTION_DIMENSION_CHANGE_ACK: + break; //TODO case PlayerActionPacket.ACTION_START_GLIDE: PlayerToggleGlideEvent playerToggleGlideEvent = new PlayerToggleGlideEvent(this, true); this.server.getPluginManager().callEvent(playerToggleGlideEvent); @@ -2706,7 +2371,6 @@ public void handleDataPacket(DataPacket packet) { this.setGliding(true); } break packetswitch; - case PlayerActionPacket.ACTION_STOP_GLIDE: playerToggleGlideEvent = new PlayerToggleGlideEvent(this, false); this.server.getPluginManager().callEvent(playerToggleGlideEvent); @@ -2716,58 +2380,47 @@ public void handleDataPacket(DataPacket packet) { this.setGliding(false); } break packetswitch; - case PlayerActionPacket.ACTION_WORLD_IMMUTABLE: - break; //TODO case PlayerActionPacket.ACTION_CONTINUE_BREAK: - block = this.level.getBlock(pos); - this.level.addParticle(new PunchBlockParticle(pos, block, face)); + if (this.isBreakingBlock()) { + block = this.level.getBlock(pos); + this.level.addParticle(new PunchBlockParticle(pos, block, face)); + } break; } this.startAction = -1; this.setDataFlag(Player.DATA_FLAGS, Player.DATA_FLAG_ACTION, false); break; - case ProtocolInfo.REMOVE_BLOCK_PACKET: + case ProtocolInfo.MOB_ARMOR_EQUIPMENT_PACKET: + break; + + case ProtocolInfo.MODAL_FORM_RESPONSE_PACKET: if (!this.spawned || !this.isAlive()) { break; } - this.craftingType = CRAFTING_SMALL; - - Vector3 vector = new Vector3(((RemoveBlockPacket) packet).x, ((RemoveBlockPacket) packet).y, ((RemoveBlockPacket) packet).z); - - if (this.isCreative()) { - item = this.inventory.getItemInHand(); - } else { - item = this.inventory.getItemInHand(); - } - Item oldItem = item.clone(); + ModalFormResponsePacket modalFormPacket = (ModalFormResponsePacket) packet; - if (this.canInteract(vector.add(0.5, 0.5, 0.5), this.isCreative() ? 13 : 7) && (item = this.level.useBreakOn(vector, item, this, true)) != null) { - if (this.isSurvival()) { - this.getFoodData().updateFoodExpLevel(0.025); - if (!item.deepEquals(oldItem) || item.getCount() != oldItem.getCount()) { - this.inventory.setItemInHand(item); - this.inventory.sendHeldItem(this.hasSpawned.values()); - } - } - break; - } + if (formWindows.containsKey(modalFormPacket.formId)) { + FormWindow window = formWindows.get(modalFormPacket.formId); + window.setResponse(modalFormPacket.data.trim()); - this.inventory.sendContents(this); - Block target = this.level.getBlock(vector); - BlockEntity blockEntity = this.level.getBlockEntity(vector); + PlayerFormRespondedEvent event = new PlayerFormRespondedEvent(this, modalFormPacket.formId, window); + getServer().getPluginManager().callEvent(event); - this.level.sendBlocks(new Player[]{this}, new Block[]{target}, UpdateBlockPacket.FLAG_ALL_PRIORITY); + formWindows.remove(modalFormPacket.formId); + } else if (serverSettings.containsKey(modalFormPacket.formId)) { + FormWindow window = serverSettings.get(modalFormPacket.formId); + window.setResponse(modalFormPacket.data.trim()); - this.inventory.sendHeldItem(this); + PlayerSettingsRespondedEvent event = new PlayerSettingsRespondedEvent(this, modalFormPacket.formId, window); + getServer().getPluginManager().callEvent(event); - if (blockEntity instanceof BlockEntitySpawnable) { - ((BlockEntitySpawnable) blockEntity).spawnTo(this); + //Set back new settings if not been cancelled + if (!event.isCancelled() && window instanceof FormWindowCustom) + ((FormWindowCustom) window).setElementsFromResponse(); } - break; - case ProtocolInfo.MOB_ARMOR_EQUIPMENT_PACKET: break; case ProtocolInfo.INTERACT_PACKET: @@ -2775,118 +2428,66 @@ public void handleDataPacket(DataPacket packet) { break; } + this.craftingType = CRAFTING_SMALL; + this.resetCraftingGridType(); + InteractPacket interactPacket = (InteractPacket) packet; - + Entity targetEntity = this.level.getEntity(interactPacket.target); if (targetEntity == null || !this.isAlive() || !targetEntity.isAlive()) { break; } - this.craftingType = CRAFTING_SMALL; - if (targetEntity instanceof EntityItem || targetEntity instanceof EntityArrow || targetEntity instanceof EntityXPOrb) { - this.kick(PlayerKickEvent.Reason.INVALID_PVE, "Attempting to attack an invalid entity"); + this.kick(PlayerKickEvent.Reason.INVALID_PVE, "Attempting to interact with an invalid entity"); this.server.getLogger().warning(this.getServer().getLanguage().translateString("nukkit.player.invalidEntity", this.getName())); break; } - + item = this.inventory.getItemInHand(); switch (interactPacket.action) { case InteractPacket.ACTION_MOUSEOVER: this.getServer().getPluginManager().callEvent(new PlayerMouseOverEntityEvent(this, targetEntity)); break; - case InteractPacket.ACTION_LEFT_CLICK: - if (this.getGamemode() == Player.VIEW) { + case InteractPacket.ACTION_VEHICLE_EXIT: + if (!(targetEntity instanceof EntityRideable) || this.riding == null) { break; } - float itemDamage = item.getAttackDamage(); - - for (Enchantment enchantment : item.getEnchantments()) { - itemDamage += enchantment.getDamageBonus(targetEntity); + ((EntityRideable) riding).mountEntity(this); + break; + } + break; + case ProtocolInfo.BLOCK_PICK_REQUEST_PACKET: + BlockPickRequestPacket pickRequestPacket = (BlockPickRequestPacket) packet; + Block block = this.level.getBlock(this.temporalVector.setComponents(pickRequestPacket.x, pickRequestPacket.y, pickRequestPacket.z)); + item = block.toItem(); + + if (pickRequestPacket.addUserData) { + BlockEntity blockEntity = this.getLevel().getBlockEntity(new Vector3(pickRequestPacket.x, pickRequestPacket.y, pickRequestPacket.z)); + if (blockEntity != null) { + CompoundTag nbt = blockEntity.getCleanedNBT(); + if (nbt != null) { + Item item1 = this.getInventory().getItemInHand(); + item1.setCustomBlockData(nbt); + item1.setLore("+(DATA)"); + this.getInventory().setItemInHand(item1); } + } + } - Map damage = new EnumMap<>(DamageModifier.class); - damage.put(DamageModifier.BASE, itemDamage); + PlayerBlockPickEvent pickEvent = new PlayerBlockPickEvent(this, block, item); + if (!this.isCreative()) { + this.server.getLogger().debug("Got block-pick request from " + this.getName() + " when not in creative mode (gamemode " + this.getGamemode() + ")"); + pickEvent.setCancelled(); + } - if (!this.canInteract(targetEntity, isCreative() ? 8 : 5)) { - break; - } else if (targetEntity instanceof Player) { - if ((((Player) targetEntity).getGamemode() & 0x01) > 0) { - break; - } else if (!this.server.getPropertyBoolean("pvp") || this.server.getDifficulty() == 0) { - break; - } - } - - if (!targetEntity.attack(new EntityDamageByEntityEvent(this, targetEntity, DamageCause.ENTITY_ATTACK, damage))) { - if (item.isTool() && this.isSurvival()) { - this.inventory.sendContents(this); - } - break; - } - - for (Enchantment enchantment : item.getEnchantments()) { - enchantment.doPostAttack(this, targetEntity); - } - - if (item.isTool() && this.isSurvival()) { - if (item.useOn(targetEntity) && item.getDamage() >= item.getMaxDurability()) { - this.inventory.setItemInHand(new ItemBlock(new BlockAir())); - } else { - this.inventory.setItemInHand(item); - } - } - - break; - case InteractPacket.ACTION_RIGHT_CLICK: - PlayerInteractEntityEvent playerInteractEntityEvent = new PlayerInteractEntityEvent(this, targetEntity, item); - getServer().getPluginManager().callEvent(playerInteractEntityEvent); - - if (playerInteractEntityEvent.isCancelled()) { - break; - } - - if (targetEntity.onInteract(this, item) && this.isSurvival()) { - if (item.isTool()) { - if (item.useOn(targetEntity) && item.getDamage() >= item.getMaxDurability()) { - item = new ItemBlock(new BlockAir()); - } - } else { - if (item.count > 1) { - item.count--; - } else { - item = new ItemBlock(new BlockAir()); - } - } - - this.inventory.setItemInHand(item); - } - break; - case InteractPacket.ACTION_VEHICLE_EXIT: - if (!(targetEntity instanceof EntityVehicle) || this.riding == null) { - break; - } + this.server.getPluginManager().callEvent(pickEvent); - ((EntityVehicle) riding).mountEntity(this); - break; - } - break; - case ProtocolInfo.BLOCK_PICK_REQUEST_PACKET: - BlockPickRequestPacket pickRequestPacket = (BlockPickRequestPacket) packet; - if (this.isCreative()) { - BlockEntity be = this.getLevel().getBlockEntity(new Vector3(pickRequestPacket.x, pickRequestPacket.y, pickRequestPacket.z)); - if (be != null) { - CompoundTag nbt = be.getCleanedNBT(); - if(nbt != null){ - Item item1 = this.getInventory().getItemInHand(); - item1.setCustomBlockData(nbt); - item1.setLore("+(DATA)"); - this.getInventory().setItemInHand(item1); - } - } + if (!pickEvent.isCancelled()) { + this.inventory.setItemInHand(pickEvent.getItem()); } break; case ProtocolInfo.ANIMATE_PACKET: @@ -2914,126 +2515,28 @@ public void handleDataPacket(DataPacket packet) { break; } this.craftingType = CRAFTING_SMALL; + this.resetCraftingGridType(); - this.setDataFlag(DATA_FLAGS, DATA_FLAG_ACTION, false); //TODO: check if this should be true EntityEventPacket entityEventPacket = (EntityEventPacket) packet; switch (entityEventPacket.event) { - case EntityEventPacket.USE_ITEM: //Eating - Item itemInHand = this.inventory.getItemInHand(); - PlayerItemConsumeEvent consumeEvent = new PlayerItemConsumeEvent(this, itemInHand); - this.server.getPluginManager().callEvent(consumeEvent); - if (consumeEvent.isCancelled()) { - this.inventory.sendContents(this); + case EntityEventPacket.EATING_ITEM: + if (entityEventPacket.data == 0) { break; } - if (itemInHand.getId() == Item.POTION) { - Potion potion = Potion.getPotion(itemInHand.getDamage()).setSplash(false); - - if (this.getGamemode() == SURVIVAL) { - if (itemInHand.getCount() > 1) { - ItemGlassBottle bottle = new ItemGlassBottle(); - if (this.inventory.canAddItem(bottle)) { - this.inventory.addItem(bottle); - } - --itemInHand.count; - } else { - itemInHand = new ItemGlassBottle(); - } - } - - if (potion != null) { - potion.applyPotion(this); - } - - } else { - EntityEventPacket pk = new EntityEventPacket(); - pk.eid = this.getId(); - pk.event = EntityEventPacket.USE_ITEM; - this.dataPacket(pk); - Server.broadcastPacket(this.getViewers().values(), pk); - - Food food = Food.getByRelative(itemInHand); - if (food != null) if (food.eatenBy(this)) --itemInHand.count; - - } - - this.inventory.setItemInHand(itemInHand); - this.inventory.sendHeldItem(this); - + /*this.dataPacket(packet); //bug? + Server.broadcastPacket(this.getViewers().values(), packet);*/ break; } break; - case ProtocolInfo.DROP_ITEM_PACKET: - if (!this.spawned || !this.isAlive()) { - break; - } - DropItemPacket dropItem = (DropItemPacket) packet; - - if (dropItem.item.getId() <= 0) { - break; - } - - item = (this.isCreative() || this.inventory.contains(dropItem.item)) ? dropItem.item : this.inventory.getItemInHand(); - PlayerDropItemEvent dropItemEvent = new PlayerDropItemEvent(this, item); - this.server.getPluginManager().callEvent(dropItemEvent); - if (dropItemEvent.isCancelled()) { - this.inventory.sendContents(this); - break; - } - - if (!this.isCreative()) { - this.inventory.removeItem(item); - } - Vector3 motion = this.getDirectionVector().multiply(0.4); - - this.level.dropItem(this.add(0, 1.3, 0), item, motion, 40); - - this.setDataFlag(DATA_FLAGS, DATA_FLAG_ACTION, false); - break; - case ProtocolInfo.COMMAND_STEP_PACKET: + case ProtocolInfo.COMMAND_REQUEST_PACKET: if (!this.spawned || !this.isAlive()) { break; } this.craftingType = 0; - CommandStepPacket commandStepPacket = (CommandStepPacket) packet; - String commandText = commandStepPacket.command; - Command command = this.getServer().getCommandMap().getCommand(commandText); - if (command != null) { - if (commandStepPacket.args != null && commandStepPacket.args.size() > 0) { - CommandParameter[] pars = command.getCommandParameters(commandStepPacket.overload); - if (pars != null) { - for (CommandParameter par : pars) { - JsonElement arg = commandStepPacket.args.get(par.name); - if (arg != null) { - switch (par.type) { - case CommandParameter.ARG_TYPE_TARGET: - CommandArg rules = new Gson().fromJson(arg, CommandArg.class); - commandText += " " + rules.getRules()[0].getValue(); - break; - case CommandParameter.ARG_TYPE_BLOCK_POS: - CommandArgBlockVector bv = new Gson().fromJson(arg, CommandArgBlockVector.class); - commandText += " " + bv.getX() + " " + bv.getY() + " " + bv.getZ(); - break; - case CommandParameter.ARG_TYPE_STRING: - case CommandParameter.ARG_TYPE_STRING_ENUM: - case CommandParameter.ARG_TYPE_RAW_TEXT: - String string = new Gson().fromJson(arg, String.class); - commandText += " " + string; - break; - default: - commandText += " " + arg.toString(); - break; - } - } - } - } else { - this.sendMessage(this.getServer().getLanguage().translateString(command.getUsage())); - } - } - } - PlayerCommandPreprocessEvent playerCommandPreprocessEvent = new PlayerCommandPreprocessEvent(this, "/" + commandText); + CommandRequestPacket commandRequestPacket = (CommandRequestPacket) packet; + PlayerCommandPreprocessEvent playerCommandPreprocessEvent = new PlayerCommandPreprocessEvent(this, commandRequestPacket.command); this.server.getPluginManager().callEvent(playerCommandPreprocessEvent); if (playerCommandPreprocessEvent.isCancelled()) { break; @@ -3048,34 +2551,25 @@ public void handleDataPacket(DataPacket packet) { break; } - this.craftingType = CRAFTING_SMALL; TextPacket textPacket = (TextPacket) packet; if (textPacket.type == TextPacket.TYPE_CHAT) { - textPacket.message = this.removeFormat ? TextFormat.clean(textPacket.message) : textPacket.message; - for (String msg : textPacket.message.split("\n")) { - if (!"".equals(msg.trim()) && msg.length() <= 255 && this.messageCounter-- > 0) { - PlayerChatEvent chatEvent = new PlayerChatEvent(this, msg); - this.server.getPluginManager().callEvent(chatEvent); - if (!chatEvent.isCancelled()) { - this.server.broadcastMessage(this.getServer().getLanguage().translateString(chatEvent.getFormat(), new String[]{chatEvent.getPlayer().getDisplayName(), chatEvent.getMessage()}), chatEvent.getRecipients()); - } - } - } + this.chat(textPacket.message); } break; case ProtocolInfo.CONTAINER_CLOSE_PACKET: ContainerClosePacket containerClosePacket = (ContainerClosePacket) packet; - if (!this.spawned || containerClosePacket.windowid == 0) { + if (!this.spawned || containerClosePacket.windowId == 0) { break; } this.craftingType = CRAFTING_SMALL; - this.currentTransaction = null; - if (this.windowIndex.containsKey(containerClosePacket.windowid)) { - this.server.getPluginManager().callEvent(new InventoryCloseEvent(this.windowIndex.get(containerClosePacket.windowid), this)); - this.removeWindow(this.windowIndex.get(containerClosePacket.windowid)); + this.resetCraftingGridType(); + + if (this.windowIndex.containsKey(containerClosePacket.windowId)) { + this.server.getPluginManager().callEvent(new InventoryCloseEvent(this.windowIndex.get(containerClosePacket.windowId), this)); + this.removeWindow(this.windowIndex.get(containerClosePacket.windowId)); } else { - this.windowIndex.remove(containerClosePacket.windowid); + this.windowIndex.remove(containerClosePacket.windowId); } break; @@ -3087,48 +2581,26 @@ public void handleDataPacket(DataPacket packet) { } Recipe recipe = this.server.getCraftingManager().getRecipe(craftingEventPacket.id); - - if (this.craftingType == CRAFTING_ANVIL) { - Inventory inv = this.windowIndex.get(craftingEventPacket.windowId); - AnvilInventory anvilInventory = inv instanceof AnvilInventory ? (AnvilInventory) inv : null; - - if (anvilInventory == null) { - anvilInventory = null; - - for (Inventory window : this.windowIndex.values()) { - if (window instanceof AnvilInventory) { - anvilInventory = (AnvilInventory) window; - break; - } - } - - if (anvilInventory == null) { //If it'sf _still_ null, then the player doesn't have a valid anvil window, cannot proceed. - this.getServer().getLogger().debug("Couldn't find an anvil window for " + this.getName() + ", exiting"); - this.inventory.sendContents(this); - break; - } + Recipe[] recipes = this.server.getCraftingManager().getRecipesByResult(craftingEventPacket.output[0]); + + boolean isValid = false; + for (Recipe rec : recipes){ + if (rec.getId().equals(recipe.getId())) { + isValid = true; + break; } + } + if (isValid) recipes = new Recipe[]{recipe}; - if (recipe == null) { - //Item renamed - - if (!anvilInventory.onRename(this, craftingEventPacket.output[0])) { - this.getServer().getLogger().debug(this.getName() + " failed to rename an item in an anvil"); - this.inventory.sendContents(this); - } - } else { - //TODO: Anvil crafting recipes - } - break; - } else if (!this.windowIndex.containsKey(craftingEventPacket.windowId)) { + if (!this.windowIndex.containsKey(craftingEventPacket.windowId)) { this.inventory.sendContents(this); containerClosePacket = new ContainerClosePacket(); - containerClosePacket.windowid = craftingEventPacket.windowId; + containerClosePacket.windowId = craftingEventPacket.windowId; this.dataPacket(containerClosePacket); break; } - - if ((recipe == null) || (((recipe instanceof BigShapelessRecipe) || (recipe instanceof BigShapedRecipe)) && this.craftingType == CRAFTING_SMALL)) { + + if (isValid && (recipe == null || (((recipe instanceof BigShapelessRecipe) || (recipe instanceof BigShapedRecipe)) && this.craftingType == CRAFTING_SMALL))) { this.inventory.sendContents(this); break; } @@ -3145,85 +2617,18 @@ public void handleDataPacket(DataPacket packet) { } boolean canCraft = true; - - if (craftingEventPacket.input.length == 0) { - Recipe[] recipes = getServer().getCraftingManager().getRecipesByResult(craftingEventPacket.output[0]); - - recipe = null; - + Map realSerialized = new HashMap<>(); + + for (Recipe rec : recipes) { ArrayList ingredientz = new ArrayList<>(); - - recipeloop: - for (Recipe rec : recipes) { - ingredientz.clear(); - - if (rec instanceof ShapedRecipe) { - Map> ingredients = ((ShapedRecipe) rec).getIngredientMap(); - for (Map map : ingredients.values()) { - for (Item ingredient : map.values()) { - if (ingredient != null && ingredient.getId() != Item.AIR) { - ingredientz.add(ingredient); - } - } - } - } else if (rec instanceof ShapelessRecipe) { - ShapelessRecipe recipe0 = (ShapelessRecipe) rec; - - for (Item ingredient : recipe0.getIngredientList()) { - if (ingredient != null && ingredient.getId() != Item.AIR) { - ingredientz.add(ingredient); - } - } - } - - Map serialized = new HashMap<>(); - - for (Item ingredient : ingredientz) { - String hash = ingredient.getId() + ":" + ingredient.getDamage(); - Item r = serialized.get(hash); - - if (r != null) { - r.count += ingredient.getCount(); - continue; - } - - serialized.put(hash, ingredient); - } - - for (Item ingredient : serialized.values()) { - if (!this.inventory.contains(ingredient)) { - continue recipeloop; - } - } - - recipe = rec; - - CraftItemEvent craftItemEvent = new CraftItemEvent(this, serialized.values().stream().toArray(Item[]::new), recipe); - getServer().getPluginManager().callEvent(craftItemEvent); - - if (craftItemEvent.isCancelled()) { - this.inventory.sendContents(this); - break packetswitch; - } - - for (Item ingredient : serialized.values()) { - this.inventory.removeItem(ingredient); - } - - this.inventory.addItem(recipe.getResult()); - break; - } - - if (recipe == null) { - this.server.getLogger().debug("(1) Unmatched desktop recipe " + craftingEventPacket.id + " from player " + this.getName()); - this.inventory.sendContents(this); + + if (rec == null || (((rec instanceof BigShapelessRecipe) || (rec instanceof BigShapedRecipe)) && this.craftingType == CRAFTING_SMALL)) { + continue; } - } else { - ArrayList ingredientz = new ArrayList<>(); - - if (recipe instanceof ShapedRecipe) { - Map> ingredients = ((ShapedRecipe) recipe).getIngredientMap(); + if (rec instanceof ShapedRecipe) { + Map> ingredients = ((ShapedRecipe) rec).getIngredientMap(); + for (Map map : ingredients.values()) { for (Item ingredient : map.values()) { if (ingredient != null && ingredient.getId() != Item.AIR) { @@ -3255,500 +2660,566 @@ public void handleDataPacket(DataPacket packet) { serialized.put(hash, ingredient); } + boolean isPossible = true; for (Item ingredient : serialized.values()) { - if (!this.inventory.contains(ingredient)) { - canCraft = false; - break; + if (!this.craftingGrid.contains(ingredient)) { + if (isValid) { + canCraft = false; + break; + } + else { + isPossible = false; + break; + } } } + if (!isPossible) continue; + recipe = rec; + realSerialized = serialized; + break; + } - if (!canCraft) { - this.server.getLogger().debug("(1) Unmatched recipe " + craftingEventPacket.id + " from player " + this.getName() + " not anough ingredients"); - return; - } + if (!canCraft) { + this.server.getLogger().debug("(1) Unmatched recipe " + craftingEventPacket.id + " from player " + this.getName() + " not anough ingredients"); + return; + } - CraftItemEvent craftItemEvent = new CraftItemEvent(this, serialized.values().stream().toArray(Item[]::new), recipe); - getServer().getPluginManager().callEvent(craftItemEvent); + CraftItemEvent craftItemEvent = new CraftItemEvent(this, realSerialized.values().stream().toArray(Item[]::new), recipe); + getServer().getPluginManager().callEvent(craftItemEvent); - if (craftItemEvent.isCancelled()) { - this.inventory.sendContents(this); + if (craftItemEvent.isCancelled()) { + this.inventory.sendContents(this); + break; + } + + for (Item ingredient : realSerialized.values()) { + this.craftingGrid.removeFromAll(ingredient); + } + + this.inventory.addItem(recipe.getResult()); + + switch (recipe.getResult().getId()) { + case Item.WORKBENCH: + this.awardAchievement("buildWorkBench"); + break; + case Item.WOODEN_PICKAXE: + this.awardAchievement("buildPickaxe"); + break; + case Item.FURNACE: + this.awardAchievement("buildFurnace"); + break; + case Item.WOODEN_HOE: + this.awardAchievement("buildHoe"); + break; + case Item.BREAD: + this.awardAchievement("makeBread"); break; + case Item.CAKE: + //TODO: detect complex recipes like cake that leave remains + this.awardAchievement("bakeCake"); + this.inventory.addItem(new ItemBucket(0, 3)); + break; + case Item.STONE_PICKAXE: + case Item.GOLD_PICKAXE: + case Item.IRON_PICKAXE: + case Item.DIAMOND_PICKAXE: + this.awardAchievement("buildBetterPickaxe"); + break; + case Item.WOODEN_SWORD: + this.awardAchievement("buildSword"); + break; + case Item.DIAMOND: + this.awardAchievement("diamond"); + break; + default: + break; + } + + break; + case ProtocolInfo.BLOCK_ENTITY_DATA_PACKET: + if (!this.spawned || !this.isAlive()) { + break; + } + BlockEntityDataPacket blockEntityDataPacket = (BlockEntityDataPacket) packet; + this.craftingType = CRAFTING_SMALL; + this.resetCraftingGridType(); + + pos = new Vector3(blockEntityDataPacket.x, blockEntityDataPacket.y, blockEntityDataPacket.z); + if (pos.distanceSquared(this) > 10000) { + break; + } + + BlockEntity t = this.level.getBlockEntity(pos); + if (t instanceof BlockEntitySpawnable) { + CompoundTag nbt; + try { + nbt = NBTIO.read(blockEntityDataPacket.namedTag, ByteOrder.LITTLE_ENDIAN, true); + } catch (IOException e) { + throw new RuntimeException(e); } - for (Item ingredient : serialized.values()) { - this.inventory.removeItem(ingredient); + if (!((BlockEntitySpawnable) t).updateCompoundTag(nbt, this)) { + ((BlockEntitySpawnable) t).spawnTo(this); } + } + break; + case ProtocolInfo.REQUEST_CHUNK_RADIUS_PACKET: + RequestChunkRadiusPacket requestChunkRadiusPacket = (RequestChunkRadiusPacket) packet; + ChunkRadiusUpdatedPacket chunkRadiusUpdatePacket = new ChunkRadiusUpdatedPacket(); + this.chunkRadius = Math.max(3, Math.min(requestChunkRadiusPacket.radius, this.viewDistance)); + chunkRadiusUpdatePacket.radius = this.chunkRadius; + this.dataPacket(chunkRadiusUpdatePacket); + break; + case ProtocolInfo.SET_PLAYER_GAME_TYPE_PACKET: + SetPlayerGameTypePacket setPlayerGameTypePacket = (SetPlayerGameTypePacket) packet; + if (setPlayerGameTypePacket.gamemode != this.gamemode) { + if (!this.hasPermission("nukkit.command.gamemode")) { + SetPlayerGameTypePacket setPlayerGameTypePacket1 = new SetPlayerGameTypePacket(); + setPlayerGameTypePacket1.gamemode = this.gamemode & 0x01; + this.dataPacket(setPlayerGameTypePacket1); + this.getAdventureSettings().update(); + break; + } + this.setGamemode(setPlayerGameTypePacket.gamemode, true); + Command.broadcastCommandMessage(this, new TranslationContainer("commands.gamemode.success.self", Server.getGamemodeString(this.gamemode))); + } + break; + case ProtocolInfo.ITEM_FRAME_DROP_ITEM_PACKET: + ItemFrameDropItemPacket itemFrameDropItemPacket = (ItemFrameDropItemPacket) packet; + Vector3 vector3 = this.temporalVector.setComponents(itemFrameDropItemPacket.x, itemFrameDropItemPacket.y, itemFrameDropItemPacket.z); + BlockEntity blockEntityItemFrame = this.level.getBlockEntity(vector3); + BlockEntityItemFrame itemFrame = (BlockEntityItemFrame) blockEntityItemFrame; + if (itemFrame != null) { + block = itemFrame.getBlock(); + Item itemDrop = itemFrame.getItem(); + ItemFrameDropItemEvent itemFrameDropItemEvent = new ItemFrameDropItemEvent(this, block, itemFrame, itemDrop); + this.server.getPluginManager().callEvent(itemFrameDropItemEvent); + if (!itemFrameDropItemEvent.isCancelled()) { + if (itemDrop.getId() != Item.AIR) { + vector3 = this.temporalVector.setComponents(itemFrame.x + 0.5, itemFrame.y, itemFrame.z + 0.5); + this.level.dropItem(vector3, itemDrop); + itemFrame.setItem(new ItemBlock(new BlockAir())); + itemFrame.setItemRotation(0); + this.getLevel().addSound(new ItemFrameItemRemovedSound(this)); + } + } else { + itemFrame.spawnTo(this); + } + } + break; + case ProtocolInfo.MAP_INFO_REQUEST_PACKET: + MapInfoRequestPacket pk = (MapInfoRequestPacket) packet; + Item mapItem = null; - this.inventory.addItem(recipe.getResult()); + for (Item item1 : this.inventory.getContents().values()) { + if (item1 instanceof ItemMap && ((ItemMap) item1).getMapId() == pk.mapId) { + mapItem = item1; + } + } - /*if (recipe instanceof ShapedRecipe) { - int offsetX = 0; - int offsetY = 0; + if (mapItem == null) { + for (BlockEntity be : this.level.getBlockEntities().values()) { + if (be instanceof BlockEntityItemFrame) { + BlockEntityItemFrame itemFrame1 = (BlockEntityItemFrame) be; - if (this.craftingType == CRAFTING_BIG) { - int minX = -1, minY = -1, maxX = 0, maxY = 0; - for (int x = 0; x < 3 && canCraft; ++x) { - for (int y = 0; y < 3; ++y) { - Item readItem = craftingEventPacket.input[y * 3 + x]; - if (readItem.getId() != Item.AIR) { - if (minY == -1 || minY > y) { - minY = y; - } - if (maxY < y) { - maxY = y; - } - if (minX == -1) { - minX = x; - } - if (maxX < x) { - maxX = x; - } - } - } - } - if (maxX == minX) { - offsetX = minX; - } - if (maxY == minY) { - offsetY = minY; + if (itemFrame1.getItem() instanceof ItemMap && ((ItemMap) itemFrame1.getItem()).getMapId() == pk.mapId) { + ((ItemMap) itemFrame1.getItem()).sendImage(this); + break; } } + } + } - //To fix some items can't craft - for (int x = 0; x < 3 - offsetX && canCraft; ++x) { - for (int y = 0; y < 3 - offsetY; ++y) { - item = craftingEventPacket.input[(y + offsetY) * 3 + (x + offsetX)]; - Item ingredient = ((ShapedRecipe) recipe).getIngredient(x, y); - //todo: check this https://github.com/PocketMine/PocketMine-MP/commit/58709293cf4eee2e836a94226bbba4aca0f53908 - if (item.getCount() > 0) { - if (ingredient == null || !ingredient.deepEquals(item, ingredient.hasMeta(), ingredient.getCompoundTag() != null)) { - canCraft = false; - break; - } + if (mapItem != null) { + PlayerMapInfoRequestEvent event; + getServer().getPluginManager().callEvent(event = new PlayerMapInfoRequestEvent(this, mapItem)); - } + if (!event.isCancelled()) { + ((ItemMap) mapItem).sendImage(this); + } + } + + break; + case ProtocolInfo.LEVEL_SOUND_EVENT_PACKET: + //LevelSoundEventPacket levelSoundEventPacket = (LevelSoundEventPacket) packet; + //We just need to broadcast this packet to all viewers. + this.level.addChunkPacket(this.getFloorX() >> 4, this.getFloorZ() >> 4, packet); + break; + case ProtocolInfo.INVENTORY_TRANSACTION_PACKET: + InventoryTransactionPacket transactionPacket = (InventoryTransactionPacket) packet; + + boolean isCrafting = false; + List actions = new ArrayList<>(); + for (NetworkInventoryAction networkInventoryAction : transactionPacket.actions) { + try { + InventoryAction a = networkInventoryAction.createInventoryAction(this); + if (a != null) { + if (a instanceof SlotChangeAction) { + if (((SlotChangeAction) a).getInventory() instanceof CraftingGrid) + isCrafting = true; } + actions.add(a); } + } catch (Throwable e) { + MainLogger.getLogger().debug("Unhandled inventory action from " + this.getName() + ": " + e.getMessage()); + this.sendAllInventories(); + break packetswitch; + } + } - //If can't craft by auto resize, will try to craft this item in another way - if (!canCraft) { - canCraft = true; - for (int x = 0; x < 3 && canCraft; ++x) { - for (int y = 0; y < 3; ++y) { - item = craftingEventPacket.input[y * 3 + x]; - Item ingredient = ((ShapedRecipe) recipe).getIngredient(x, y); - if (item.getCount() > 0) { - if (ingredient == null || !ingredient.deepEquals(item, ingredient.hasMeta(), ingredient.getCompoundTag() != null)) { - canCraft = false; - break; - } + switch (transactionPacket.transactionType) { + case InventoryTransactionPacket.TYPE_NORMAL: + if (this.isSpectator()) { + this.sendAllInventories(); + break; + } + InventoryTransaction transaction = new SimpleInventoryTransaction(this, actions); - } + if (!transaction.execute() && !isCrafting) { + for (Inventory inventory : transaction.getInventories()) { + inventory.sendContents(this); + if (inventory instanceof PlayerInventory) { + ((PlayerInventory) inventory).sendArmorContents(this); } } - } - } else if (recipe instanceof ShapelessRecipe) { - List needed = ((ShapelessRecipe) recipe).getIngredientList(); + MainLogger.getLogger().debug("Failed to execute inventory transaction from " + this.getName() + " with actions: " + Arrays.toString(actions.stream().toArray())); - for (int x = 0; x < 3 && canCraft; ++x) { - for (int y = 0; y < 3; ++y) { - item = craftingEventPacket.input[y * 3 + x].clone(); + //TODO: check more stuff that might need reversion + break packetswitch; //oops! + } - for (Item n : new ArrayList<>(needed)) { - if (n.deepEquals(item, n.hasMeta(), n.getCompoundTag() != null)) { - int remove = Math.min(n.getCount(), item.getCount()); - n.setCount(n.getCount() - remove); - item.setCount(item.getCount() - remove); + //TODO: fix achievement for getting iron from furnace + + break packetswitch; + case InventoryTransactionPacket.TYPE_MISMATCH: + if (transactionPacket.actions.length > 0) { + this.server.getLogger().debug("Expected 0 actions for mismatch, got " + transactionPacket.actions.length + ", " + Arrays.toString(transactionPacket.actions)); + } + this.sendAllInventories(); - if (n.getCount() == 0) { - needed.remove(n); + break packetswitch; + case InventoryTransactionPacket.TYPE_USE_ITEM: + UseItemData useItemData = (UseItemData) transactionPacket.transactionData; + + BlockVector3 blockVector = useItemData.blockPos; + face = useItemData.face; + + int type = useItemData.actionType; + switch (type) { + case InventoryTransactionPacket.USE_ITEM_ACTION_CLICK_BLOCK: + this.setDataFlag(DATA_FLAGS, DATA_FLAG_ACTION, false); + + if (this.canInteract(blockVector.add(0.5, 0.5, 0.5), this.isCreative() ? 13 : 7)) { + if (this.isCreative()) { + Item i = inventory.getItemInHand(); + if (this.level.useItemOn(blockVector.asVector3(), i, face, useItemData.clickPos.x, useItemData.clickPos.y, useItemData.clickPos.z, this) != null) { + break packetswitch; + } + } else if (inventory.getItemInHand().equals(useItemData.itemInHand)) { + Item i = inventory.getItemInHand(); + Item oldItem = i.clone(); + //TODO: Implement adventure mode checks + if ((i = this.level.useItemOn(blockVector.asVector3(), i, face, useItemData.clickPos.x, useItemData.clickPos.y, useItemData.clickPos.z, this)) != null) { + if (!i.equals(oldItem) || i.getCount() != oldItem.getCount()) { + inventory.setItemInHand(i); + inventory.sendHeldItem(this.getViewers().values()); + } + break packetswitch; } } } - if (item.getCount() > 0) { - canCraft = false; - break; + inventory.sendHeldItem(this); + + if (blockVector.distanceSquared(this) > 10000) { + break packetswitch; } - } - } - if (!needed.isEmpty()) { - canCraft = false; - } - } else { - canCraft = false; - } + Block target = this.level.getBlock(blockVector.asVector3()); + block = target.getSide(face); + + this.level.sendBlocks(new Player[]{this}, new Block[]{target, block}, UpdateBlockPacket.FLAG_ALL_PRIORITY); + + if (target instanceof BlockDoor) { + BlockDoor door = (BlockDoor) target; + + Block part; + + if ((door.getDamage() & 0x08) > 0) { //up + part = target.down(); - List ingredientsList = new ArrayList<>(); - if (recipe instanceof ShapedRecipe) { - for (int x = 0; x < 3; x++) { - for (int y = 0; y < 3; y++) { - Item need = ((ShapedRecipe) recipe).getIngredient(x, y); - if (need.getId() == 0) { - continue; + if (part.getId() == target.getId()) { + target = part; + + this.level.sendBlocks(new Player[]{this}, new Block[]{target}, UpdateBlockPacket.FLAG_ALL_PRIORITY); + } + } } - for (int count = need.getCount(); count > 0; count--) { - Item needAdd = need.clone(); - //todo: check if there need to set item's count to 1, I'm too tired to check that today =w= - needAdd.setCount(1); - ingredientsList.add(needAdd); + break packetswitch; + case InventoryTransactionPacket.USE_ITEM_ACTION_BREAK_BLOCK: + if (!this.spawned || !this.isAlive()) { + break packetswitch; } - } - } - } - if (recipe instanceof ShapelessRecipe) { - List recipeItem = ((ShapelessRecipe) recipe).getIngredientList(); - for (Item need : recipeItem) { - if (need.getId() == 0) { - continue; - } - Item needAdd = need.clone(); - //todo: check if there need to set item's count to 1, I'm too tired to check that today =w= - needAdd.setCount(1); - ingredientsList.add(needAdd); - } - } - Item[] ingredients = ingredientsList.stream().toArray(Item[]::new); + this.resetCraftingGridType(); - Item result = craftingEventPacket.output[0]; + Item i = this.getInventory().getItemInHand(); - if (!canCraft || !recipe.getResult().deepEquals(result)) { - this.server.getLogger().debug("(2) Unmatched recipe " + recipe.getId() + " from player " + this.getName() + ": expected " + recipe.getResult() + ", got " + result + ", using: " + Arrays.asList(ingredients).toString()); - this.inventory.sendContents(this); - break; - } - - int[] used = new int[this.inventory.getSize()]; + Item oldItem = i.clone(); - for (Item ingredient : ingredients) { - slot = -1; - for (int index : this.inventory.getContents().keySet()) { - Item i = this.inventory.getContents().get(index); - if (ingredient.getId() != 0 && ingredient.deepEquals(i, ingredient.hasMeta()) && (i.getCount() - used[index]) >= 1) { - slot = index; - used[index]++; - break; - } - } + if (this.canInteract(blockVector.add(0.5, 0.5, 0.5), this.isCreative() ? 13 : 7) && (i = this.level.useBreakOn(blockVector.asVector3(), i, this, true)) != null) { + if (this.isSurvival()) { + this.getFoodData().updateFoodExpLevel(0.025); + if (!i.equals(oldItem) || i.getCount() != oldItem.getCount()) { + inventory.setItemInHand(i); + inventory.sendHeldItem(this.getViewers().values()); + } + } + break packetswitch; + } - if (ingredient.getId() != 0 && slot == -1) { - canCraft = false; - break; - } - } + inventory.sendContents(this); + target = this.level.getBlock(blockVector.asVector3()); + BlockEntity blockEntity = this.level.getBlockEntity(blockVector.asVector3()); - if (!canCraft) { - this.server.getLogger().debug("(3) Unmatched recipe " + recipe.getId() + " from player " + this.getName() + ": client does not have enough items, using: " + Arrays.asList(ingredients).toString()); - this.inventory.sendContents(this); - break; - } - CraftItemEvent craftItemEvent; - this.server.getPluginManager().callEvent(craftItemEvent = new CraftItemEvent(this, ingredients, recipe)); + this.level.sendBlocks(new Player[]{this}, new Block[]{target}, UpdateBlockPacket.FLAG_ALL_PRIORITY); - if (craftItemEvent.isCancelled()) { - this.inventory.sendContents(this); - break; - } + inventory.sendHeldItem(this); - for (int i = 0; i < used.length; i++) { - int count = used[i]; - if (count == 0) { - continue; - } + if (blockEntity instanceof BlockEntitySpawnable) { + ((BlockEntitySpawnable) blockEntity).spawnTo(this); + } - item = this.inventory.getItem(i); + break packetswitch; + case InventoryTransactionPacket.USE_ITEM_ACTION_CLICK_AIR: + Vector3 directionVector = this.getDirectionVector(); - Item newItem; - if (item.getCount() > count) { - newItem = item.clone(); - newItem.setCount(item.getCount() - count); - } else { - newItem = new ItemBlock(new BlockAir(), 0, 0); - } + if (this.isCreative()) { + item = this.inventory.getItemInHand(); + } else if (!this.inventory.getItemInHand().equals(useItemData.itemInHand)) { + this.inventory.sendHeldItem(this); + break packetswitch; + } else { + item = this.inventory.getItemInHand(); + } - this.inventory.setItem(i, newItem); - } + PlayerInteractEvent interactEvent = new PlayerInteractEvent(this, item, directionVector, face, Action.RIGHT_CLICK_AIR); - Item[] extraItem = this.inventory.addItem(recipe.getResult()); - if (extraItem.length > 0) { - for (Item i : extraItem) { - this.level.dropItem(this, i); - } - }*/ - } + this.server.getPluginManager().callEvent(interactEvent); - if (recipe != null) { - switch (recipe.getResult().getId()) { - case Item.WORKBENCH: - this.awardAchievement("buildWorkBench"); - break; - case Item.WOODEN_PICKAXE: - this.awardAchievement("buildPickaxe"); - break; - case Item.FURNACE: - this.awardAchievement("buildFurnace"); - break; - case Item.WOODEN_HOE: - this.awardAchievement("buildHoe"); - break; - case Item.BREAD: - this.awardAchievement("makeBread"); - break; - case Item.CAKE: - //TODO: detect complex recipes like cake that leave remains - this.awardAchievement("bakeCake"); - this.inventory.addItem(new ItemBucket(0, 3)); - break; - case Item.STONE_PICKAXE: - case Item.GOLD_PICKAXE: - case Item.IRON_PICKAXE: - case Item.DIAMOND_PICKAXE: - this.awardAchievement("buildBetterPickaxe"); - break; - case Item.WOODEN_SWORD: - this.awardAchievement("buildSword"); - break; - case Item.DIAMOND: - this.awardAchievement("diamond"); - break; - default: - break; - } - } + if (interactEvent.isCancelled()) { + this.inventory.sendHeldItem(this); + break packetswitch; + } - break; - case ProtocolInfo.CONTAINER_SET_SLOT_PACKET: - if (!this.spawned || !this.isAlive()) { - break; - } + if (item.onClickAir(this, directionVector) && this.isSurvival()) { + this.inventory.setItemInHand(item); + } - ContainerSetSlotPacket containerSetSlotPacket = (ContainerSetSlotPacket) packet; - if (containerSetSlotPacket.slot < 0) { - break; - } + this.setDataFlag(DATA_FLAGS, DATA_FLAG_ACTION, true); + this.startAction = this.server.getTick(); - Inventory inv; - BaseTransaction transaction; - if (containerSetSlotPacket.windowid == 0) { //Our inventory - inv = this.inventory; - if (containerSetSlotPacket.slot >= this.inventory.getSize()) { - break; - } - if (this.isCreative()) { - if (Item.getCreativeItemIndex(containerSetSlotPacket.item) != -1) { - inv.setItem(containerSetSlotPacket.slot, containerSetSlotPacket.item); - this.inventory.setHotbarSlotIndex(containerSetSlotPacket.slot, containerSetSlotPacket.slot); //links hotbar[packet.slot] to slots[packet.slot] + break packetswitch; + default: + //unknown + break; } - } - transaction = new BaseTransaction(this.inventory, containerSetSlotPacket.slot, this.inventory.getItem(containerSetSlotPacket.slot), containerSetSlotPacket.item); - } else if (containerSetSlotPacket.windowid == ContainerSetContentPacket.SPECIAL_ARMOR) { //Our armor - inv = this.inventory; - if (containerSetSlotPacket.slot >= 4) { break; - } - transaction = new BaseTransaction(this.inventory, containerSetSlotPacket.slot + this.inventory.getSize(), this.inventory.getArmorItem(containerSetSlotPacket.slot), containerSetSlotPacket.item); - } else if (this.windowIndex.containsKey(containerSetSlotPacket.windowid)) { - inv = this.windowIndex.get(containerSetSlotPacket.windowid); + case InventoryTransactionPacket.TYPE_USE_ITEM_ON_ENTITY: + UseItemOnEntityData useItemOnEntityData = (UseItemOnEntityData) transactionPacket.transactionData; - if (!(inv instanceof AnvilInventory)) { - this.craftingType = CRAFTING_SMALL; - } + Entity target = this.level.getEntity(useItemOnEntityData.entityRuntimeId); + if (target == null) { + return; + } - if (inv instanceof EnchantInventory && containerSetSlotPacket.item.hasEnchantments()) { - ((EnchantInventory) inv).onEnchant(this, inv.getItem(containerSetSlotPacket.slot), containerSetSlotPacket.item); - } + type = useItemOnEntityData.actionType; - transaction = new BaseTransaction(inv, containerSetSlotPacket.slot, inv.getItem(containerSetSlotPacket.slot), containerSetSlotPacket.item); - } else { - break; - } + if (!useItemOnEntityData.itemInHand.equalsExact(this.inventory.getItemInHand())) { + this.inventory.sendHeldItem(this); + } - if (inv != null) { - Item sourceItem = inv.getItem(containerSetSlotPacket.slot); - Item heldItem = sourceItem.clone(); - heldItem.setCount(sourceItem.getCount() - containerSetSlotPacket.item.getCount()); - if (heldItem.getCount() > 0) { //In win10, click mouse and hold on item - InventoryClickEvent inventoryClickEvent = new InventoryClickEvent(inv, containerSetSlotPacket.slot, sourceItem, heldItem, containerSetSlotPacket.item); - this.getServer().getPluginManager().callEvent(inventoryClickEvent); - //TODO Fix hold on bug and support Cancellable - } - } + item = this.inventory.getItemInHand(); - if (transaction.getSourceItem().deepEquals(transaction.getTargetItem()) && transaction.getTargetItem().getCount() == transaction.getSourceItem().getCount()) { //No changes! - //No changes, just a local inventory update sent by the server - break; - } + switch (type) { + case InventoryTransactionPacket.USE_ITEM_ON_ENTITY_ACTION_INTERACT: + PlayerInteractEntityEvent playerInteractEntityEvent = new PlayerInteractEntityEvent(this, target, item); + if (this.isSpectator()) playerInteractEntityEvent.setCancelled(); + getServer().getPluginManager().callEvent(playerInteractEntityEvent); + if (playerInteractEntityEvent.isCancelled()) { + break; + } - if (this.currentTransaction == null || this.currentTransaction.getCreationTime() < (System.currentTimeMillis() - 8 * 1000)) { - if (this.currentTransaction != null) { - for (Inventory inventory : this.currentTransaction.getInventories()) { - if (inventory instanceof PlayerInventory) { - ((PlayerInventory) inventory).sendArmorContents(this); - } - inventory.sendContents(this); - } - } - this.currentTransaction = new SimpleTransactionGroup(this); - } + if (target.onInteract(this, item) && this.isSurvival()) { + if (item.isTool()) { + if (item.useOn(target) && item.getDamage() >= item.getMaxDurability()) { + item = new ItemBlock(new BlockAir()); + } + } else { + if (item.count > 1) { + item.count--; + } else { + item = new ItemBlock(new BlockAir()); + } + } - this.currentTransaction.addTransaction(transaction); + this.inventory.setItemInHand(item); + } + break; + case InventoryTransactionPacket.USE_ITEM_ON_ENTITY_ACTION_ATTACK: + float itemDamage = item.getAttackDamage(); - if (this.currentTransaction.canExecute() || this.isCreative()) { - HashSet achievements = new HashSet<>(); + for (Enchantment enchantment : item.getEnchantments()) { + itemDamage += enchantment.getDamageBonus(target); + } - for (Transaction tr : this.currentTransaction.getTransactions()) { - Inventory inv1 = tr.getInventory(); + Map damage = new EnumMap<>(DamageModifier.class); + damage.put(DamageModifier.BASE, itemDamage); - if (inv1 instanceof FurnaceInventory) { - if (tr.getSlot() == 2) { - switch (((FurnaceInventory) inv1).getResult().getId()) { - case Item.IRON_INGOT: - achievements.add("acquireIron"); + if (!this.canInteract(target, isCreative() ? 8 : 5)) { + break; + } else if (target instanceof Player) { + if ((((Player) target).getGamemode() & 0x01) > 0) { + break; + } else if (!this.server.getPropertyBoolean("pvp") || this.server.getDifficulty() == 0) { break; + } } - } - } - } - - if (this.currentTransaction.execute(this.isCreative())) { - for (String achievement : achievements) { - this.awardAchievement(achievement); - } - } - this.currentTransaction = null; - } else { - if (containerSetSlotPacket.item.getId() != 0) { - inventory.sendSlot(containerSetSlotPacket.hotbarSlot, this); - inventory.sendSlot(containerSetSlotPacket.slot, this); - } - } + EntityDamageByEntityEvent entityDamageByEntityEvent = new EntityDamageByEntityEvent(this, target, DamageCause.ENTITY_ATTACK, damage); + if (this.isSpectator()) entityDamageByEntityEvent.setCancelled(); + if (!target.attack(entityDamageByEntityEvent)) { + if (item.isTool() && this.isSurvival()) { + this.inventory.sendContents(this); + } + break; + } - break; - case ProtocolInfo.BLOCK_ENTITY_DATA_PACKET: - if (!this.spawned || !this.isAlive()) { - break; - } - BlockEntityDataPacket blockEntityDataPacket = (BlockEntityDataPacket) packet; - this.craftingType = CRAFTING_SMALL; + for (Enchantment enchantment : item.getEnchantments()) { + enchantment.doPostAttack(this, target); + } - pos = new Vector3(blockEntityDataPacket.x, blockEntityDataPacket.y, blockEntityDataPacket.z); - if (pos.distanceSquared(this) > 10000) { - break; - } + if (item.isTool() && this.isSurvival()) { + if (item.useOn(target) && item.getDamage() >= item.getMaxDurability()) { + this.inventory.setItemInHand(new ItemBlock(new BlockAir())); + } else { + this.inventory.setItemInHand(item); + } + } + return; + default: + break; //unknown + } - BlockEntity t = this.level.getBlockEntity(pos); - if (t instanceof BlockEntitySign) { - CompoundTag nbt; - try { - nbt = NBTIO.read(blockEntityDataPacket.namedTag, ByteOrder.LITTLE_ENDIAN, true); - } catch (IOException e) { - throw new RuntimeException(e); - } + break; + case InventoryTransactionPacket.TYPE_RELEASE_ITEM: + if (this.isSpectator()) { + this.sendAllInventories(); + break packetswitch; + } + ReleaseItemData releaseItemData = (ReleaseItemData) transactionPacket.transactionData; + + try { + type = releaseItemData.actionType; + switch (type) { + case InventoryTransactionPacket.RELEASE_ITEM_ACTION_RELEASE: + if (this.isUsingItem()) { + item = this.inventory.getItemInHand(); + if (item.onReleaseUsing(this)) { + this.inventory.setItemInHand(item); + } + } else { + this.inventory.sendContents(this); + } + return; + case InventoryTransactionPacket.RELEASE_ITEM_ACTION_CONSUME: + Item itemInHand = this.inventory.getItemInHand(); + PlayerItemConsumeEvent consumeEvent = new PlayerItemConsumeEvent(this, itemInHand); + + if (itemInHand.getId() == Item.POTION) { + this.server.getPluginManager().callEvent(consumeEvent); + if (consumeEvent.isCancelled()) { + this.inventory.sendContents(this); + break; + } + Potion potion = Potion.getPotion(itemInHand.getDamage()).setSplash(false); - if (!BlockEntity.SIGN.equals(nbt.getString("id"))) { - ((BlockEntitySign) t).spawnTo(this); - } else { - SignChangeEvent signChangeEvent = new SignChangeEvent(t.getBlock(), this, new String[]{ - this.removeFormat ? TextFormat.clean(nbt.getString("Text1")) : nbt.getString("Text1"), - this.removeFormat ? TextFormat.clean(nbt.getString("Text2")) : nbt.getString("Text2"), - this.removeFormat ? TextFormat.clean(nbt.getString("Text3")) : nbt.getString("Text3"), - this.removeFormat ? TextFormat.clean(nbt.getString("Text4")) : nbt.getString("Text4") - }); - - if (!t.namedTag.contains("Creator") || !Objects.equals(this.getUniqueId().toString(), t.namedTag.getString("Creator"))) { - signChangeEvent.setCancelled(); - } + if (this.getGamemode() == SURVIVAL) { + --itemInHand.count; + this.inventory.setItemInHand(itemInHand); + this.inventory.addItem(new ItemGlassBottle()); + } - this.server.getPluginManager().callEvent(signChangeEvent); + if (potion != null) { + potion.applyPotion(this); + } - if (!signChangeEvent.isCancelled()) { - ((BlockEntitySign) t).setText(signChangeEvent.getLine(0), signChangeEvent.getLine(1), signChangeEvent.getLine(2), signChangeEvent.getLine(3)); - } else { - ((BlockEntitySign) t).spawnTo(this); - } + } else if (itemInHand.getId() == Item.BUCKET && itemInHand.getDamage() == 1) { //milk + this.server.getPluginManager().callEvent(consumeEvent); + if (consumeEvent.isCancelled()) { + this.inventory.sendContents(this); + break; + } - } - } - break; - case ProtocolInfo.REQUEST_CHUNK_RADIUS_PACKET: - RequestChunkRadiusPacket requestChunkRadiusPacket = (RequestChunkRadiusPacket) packet; - ChunkRadiusUpdatedPacket chunkRadiusUpdatePacket = new ChunkRadiusUpdatedPacket(); - this.chunkRadius = Math.max(5, Math.min(requestChunkRadiusPacket.radius, this.viewDistance)); - chunkRadiusUpdatePacket.radius = this.chunkRadius; - this.dataPacket(chunkRadiusUpdatePacket); - break; - case ProtocolInfo.SET_PLAYER_GAME_TYPE_PACKET: - SetPlayerGameTypePacket setPlayerGameTypePacket = (SetPlayerGameTypePacket) packet; - if (setPlayerGameTypePacket.gamemode != this.gamemode) { - if (!this.hasPermission("nukkit.command.gamemode")) { - SetPlayerGameTypePacket setPlayerGameTypePacket1 = new SetPlayerGameTypePacket(); - setPlayerGameTypePacket1.gamemode = this.gamemode & 0x01; - this.dataPacket(setPlayerGameTypePacket1); - this.getAdventureSettings().update(); - break; - } - this.setGamemode(setPlayerGameTypePacket.gamemode, true); - Command.broadcastCommandMessage(this, new TranslationContainer("commands.gamemode.success.self", Server.getGamemodeString(this.gamemode))); - } - break; - case ProtocolInfo.ITEM_FRAME_DROP_ITEM_PACKET: - ItemFrameDropItemPacket itemFrameDropItemPacket = (ItemFrameDropItemPacket) packet; - Vector3 vector3 = this.temporalVector.setComponents(itemFrameDropItemPacket.x, itemFrameDropItemPacket.y, itemFrameDropItemPacket.z); - BlockEntity blockEntityItemFrame = this.level.getBlockEntity(vector3); - BlockEntityItemFrame itemFrame = (BlockEntityItemFrame) blockEntityItemFrame; - if (itemFrame != null) { - Block block = itemFrame.getBlock(); - Item itemDrop = itemFrame.getItem(); - ItemFrameDropItemEvent itemFrameDropItemEvent = new ItemFrameDropItemEvent(this, block, itemFrame, itemDrop); - this.server.getPluginManager().callEvent(itemFrameDropItemEvent); - if (!itemFrameDropItemEvent.isCancelled()) { - if (itemDrop.getId() != Item.AIR) { - vector3 = this.temporalVector.setComponents(itemFrame.x + 0.5, itemFrame.y, itemFrame.z + 0.5); - this.level.dropItem(vector3, itemDrop); - itemFrame.setItem(new ItemBlock(new BlockAir())); - itemFrame.setItemRotation(0); - this.getLevel().addSound(new ItemFrameItemRemovedSound(this)); - } - } else { - itemFrame.spawnTo(this); - } - } - break; - case ProtocolInfo.MAP_INFO_REQUEST_PACKET: - MapInfoRequestPacket pk = (MapInfoRequestPacket) packet; - Item mapItem = null; + EntityEventPacket eventPacket = new EntityEventPacket(); + eventPacket.eid = this.getId(); + eventPacket.event = EntityEventPacket.USE_ITEM; + this.dataPacket(eventPacket); + Server.broadcastPacket(this.getViewers().values(), eventPacket); - for (Item item1 : this.inventory.getContents().values()) { - if (item1 instanceof ItemMap && ((ItemMap) item1).getMapId() == pk.mapId) { - mapItem = item1; - } - } + if (this.isSurvival()) { + itemInHand.count--; + this.inventory.setItemInHand(itemInHand); + this.inventory.addItem(new ItemBucket()); + } - if (mapItem == null) { - for (BlockEntity be : this.level.getBlockEntities().values()) { - if (be instanceof BlockEntityItemFrame) { - BlockEntityItemFrame itemFrame1 = (BlockEntityItemFrame) be; + this.removeAllEffects(); + } else { + this.server.getPluginManager().callEvent(consumeEvent); + if (consumeEvent.isCancelled()) { + this.inventory.sendContents(this); + break; + } - if (itemFrame1.getItem() instanceof ItemMap && ((ItemMap) itemFrame1.getItem()).getMapId() == pk.mapId) { - ((ItemMap) itemFrame1.getItem()).sendImage(this); - break; + Food food = Food.getByRelative(itemInHand); + if (food != null && food.eatenBy(this)) --itemInHand.count; + this.inventory.setItemInHand(itemInHand); + } + return; + default: + break; } + } finally { + this.setUsingItem(false); } - } + break; + default: + this.inventory.sendContents(this); + break; } + break; + case ProtocolInfo.PLAYER_HOTBAR_PACKET: + PlayerHotbarPacket hotbarPacket = (PlayerHotbarPacket) packet; - if (mapItem != null) { - PlayerMapInfoRequestEvent event; - getServer().getPluginManager().callEvent(event = new PlayerMapInfoRequestEvent(this, mapItem)); + if (hotbarPacket.windowId != ContainerIds.INVENTORY) { + return; //In PE this should never happen + } - if (!event.isCancelled()) { - ((ItemMap) mapItem).sendImage(this); - } + this.inventory.equipItem(hotbarPacket.selectedHotbarSlot); + break; + case ProtocolInfo.SERVER_SETTINGS_REQUEST_PACKET: + PlayerServerSettingsRequestEvent settingsRequestEvent = new PlayerServerSettingsRequestEvent(this, new HashMap<>(this.serverSettings)); + this.getServer().getPluginManager().callEvent(settingsRequestEvent); + + if (!settingsRequestEvent.isCancelled()) { + settingsRequestEvent.getSettings().forEach((id, window) -> { + ServerSettingsResponsePacket re = new ServerSettingsResponsePacket(); + re.formId = id; + re.data = window.getJSONData(); + this.dataPacket(re); + }); } break; default: @@ -3757,6 +3228,35 @@ public void handleDataPacket(DataPacket packet) { } } + /** + * Sends a chat message as this player. If the message begins with a / (forward-slash) it will be treated + * as a command. + */ + public boolean chat(String message) { + if (!this.spawned || !this.isAlive()) { + return false; + } + + this.resetCraftingGridType(); + this.craftingType = CRAFTING_SMALL; + + if (this.removeFormat) { + message = TextFormat.clean(message); + } + + for (String msg : message.split("\n")) { + if (!msg.trim().isEmpty() && msg.length() <= 255 && this.messageCounter-- > 0) { + PlayerChatEvent chatEvent = new PlayerChatEvent(this, msg); + this.server.getPluginManager().callEvent(chatEvent); + if (!chatEvent.isCancelled()) { + this.server.broadcastMessage(this.getServer().getLanguage().translateString(chatEvent.getFormat(), new String[]{chatEvent.getPlayer().getDisplayName(), chatEvent.getMessage()}), chatEvent.getRecipients()); + } + } + } + + return true; + } + public boolean kick() { return this.kick(""); } @@ -3788,12 +3288,12 @@ public boolean kick(PlayerKickEvent.Reason reason, String reasonString, boolean String message; if (isAdmin) { if (!this.isBanned()) { - message = "Kicked by admin." + (!"".equals(reasonString) ? " Reason: " + reasonString : ""); + message = "Kicked by admin." + (!reasonString.isEmpty() ? " Reason: " + reasonString : ""); } else { message = reasonString; } } else { - if ("".equals(reasonString)) { + if (reasonString.isEmpty()) { message = "disconnectionScreen.noReason"; } else { message = reasonString; @@ -3808,17 +3308,25 @@ public boolean kick(PlayerKickEvent.Reason reason, String reasonString, boolean return false; } + public void setViewDistance(int distance) { + this.chunkRadius = distance; + + ChunkRadiusUpdatedPacket pk = new ChunkRadiusUpdatedPacket(); + pk.radius = distance; + + this.dataPacket(pk); + } + + public int getViewDistance() { + return this.chunkRadius; + } + @Override public void sendMessage(String message) { - // TODO: Remove this workaround (broken client MCPE 1.0.0) - messageQueue.add(this.server.getLanguage().translateString(message)); - - /* TextPacket pk = new TextPacket(); pk.type = TextPacket.TYPE_RAW; pk.message = this.server.getLanguage().translateString(message); this.dataPacket(pk); - */ } @Override @@ -3851,6 +3359,18 @@ public void sendTranslation(String message, String[] parameters) { this.dataPacket(pk); } + public void sendChat(String message) { + this.sendChat("", message); + } + + public void sendChat(String source, String message) { + TextPacket pk = new TextPacket(); + pk.type = TextPacket.TYPE_CHAT; + pk.source = source; + pk.message = this.server.getLanguage().translateString(message); + this.dataPacket(pk); + } + public void sendPopup(String message) { this.sendPopup(message, ""); } @@ -3885,43 +3405,60 @@ public void resetTitleSettings() { this.dataPacket(pk); } - public void sendTitle(String text) { + public void setSubtitle(String subtitle) { SetTitlePacket pk = new SetTitlePacket(); - pk.type = SetTitlePacket.TYPE_TITLE; - pk.text = text; + pk.type = SetTitlePacket.TYPE_SUBTITLE; + pk.text = subtitle; this.dataPacket(pk); } - /** - * Sets a subtitle for the next shown title - * @param text Subtitle text - */ - public void setSubtitle(String text) { + public void setTitleAnimationTimes(int fadein, int duration, int fadeout) { SetTitlePacket pk = new SetTitlePacket(); - pk.type = SetTitlePacket.TYPE_SUBTITLE; - pk.text = text; + pk.type = SetTitlePacket.TYPE_ANIMATION_TIMES; + pk.fadeInTime = fadein; + pk.stayTime = duration; + pk.fadeOutTime = fadeout; this.dataPacket(pk); } - public void sendActionBarTitle(String text) { - SetTitlePacket pk = new SetTitlePacket(); - pk.type = SetTitlePacket.TYPE_ACTION_BAR; - pk.text = text; - this.dataPacket(pk); + public void sendTitle(String title) { + this.sendTitle(title, "", 20, 20, 5); } - /** - * Sets times for title animations - * @param fadeInTime For how long title fades in - * @param stayTime For how long title is shown - * @param fadeOutTime For how long title fades out - */ - public void setTitleAnimationTimes(int fadeInTime, int stayTime, int fadeOutTime) { + public void sendTitle(String title, String subtitle) { + this.sendTitle(title, subtitle, 20, 20, 5); + } + + public void sendTitle(String title, String subtitle, int fadein, int duration, int fadeout) { + if (!subtitle.equals("")) { + SetTitlePacket pk = new SetTitlePacket(); + pk.type = SetTitlePacket.TYPE_SUBTITLE; + pk.text = subtitle; + pk.fadeInTime = fadein; + pk.stayTime = duration; + pk.fadeOutTime = fadeout; + this.dataPacket(pk); + } + SetTitlePacket pk2 = new SetTitlePacket(); + pk2.type = SetTitlePacket.TYPE_TITLE; + pk2.text = title; + pk2.fadeInTime = fadein; + pk2.stayTime = duration; + pk2.fadeOutTime = fadeout; + this.dataPacket(pk2); + } + + public void sendActionBar(String title) { + this.sendActionBar(title, 1, 0, 1); + } + + public void sendActionBar(String title, int fadein, int duration, int fadeout) { SetTitlePacket pk = new SetTitlePacket(); - pk.type = SetTitlePacket.TYPE_ANIMATION_TIMES; - pk.fadeInTime = fadeInTime; - pk.stayTime = stayTime; - pk.fadeOutTime = fadeOutTime; + pk.type = SetTitlePacket.TYPE_ACTION_BAR; + pk.text = title; + pk.fadeInTime = fadein; + pk.stayTime = duration; + pk.fadeOutTime = fadeout; this.dataPacket(pk); } @@ -3975,9 +3512,7 @@ public void close(TextContainer message, String reason, boolean notify) { this.hiddenPlayers = new HashMap<>(); - for (Inventory window : new ArrayList<>(this.windowIndex.values())) { - this.removeWindow(window); - } + this.removeAllWindows(true); for (long index : new ArrayList<>(this.usedChunks.keySet())) { int chunkX = Level.getHashX(index); @@ -4014,8 +3549,8 @@ public void close(TextContainer message, String reason, boolean notify) { this.hasSpawned = new HashMap<>(); this.spawnPosition = null; - if (this.riding instanceof EntityVehicle) { - ((EntityVehicle) this.riding).linkedEntity = null; + if (this.riding instanceof EntityRideable) { + this.riding.linkedEntity = null; } this.riding = null; @@ -4028,7 +3563,6 @@ public void close(TextContainer message, String reason, boolean notify) { if (this.inventory != null) { this.inventory = null; - this.currentTransaction = null; } this.chunk = null; @@ -4074,7 +3608,7 @@ public void save(boolean async) { this.namedTag.putInt("foodLevel", this.getFoodData().getLevel()); this.namedTag.putFloat("foodSaturationLevel", this.getFoodData().getFoodSaturationLevel()); - if (!"".equals(this.username) && this.namedTag != null) { + if (!this.username.isEmpty() && this.namedTag != null) { this.server.saveOfflinePlayerData(this.username, this.namedTag, async); } } @@ -4263,7 +3797,8 @@ public void setHealth(float health) { } super.setHealth(health); - Attribute attr = Attribute.getAttribute(Attribute.MAX_HEALTH).setMaxValue(this.getMaxHealth()).setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0); + //TODO: Remove it in future! This a hack to solve the client-side absorption bug! WFT Mojang (Half a yellow heart cannot be shown, we can test it in local gaming) + Attribute attr = Attribute.getAttribute(Attribute.MAX_HEALTH).setMaxValue(this.getAbsorption() % 2 != 0 ? this.getMaxHealth() + 1 : this.getMaxHealth()).setValue(health > 0 ? (health < getMaxHealth() ? health : getMaxHealth()) : 0); if (this.spawned) { UpdateAttributesPacket pk = new UpdateAttributesPacket(); pk.entries = new Attribute[]{attr}; @@ -4372,7 +3907,7 @@ public boolean attack(EntityDamageEvent source) { ) { //source.setCancelled(); return false; - } else if (this.getAdventureSettings().canFly() && source.getCause() == DamageCause.FALL) { + } else if (this.getAdventureSettings().get(Type.ALLOW_FLIGHT) && source.getCause() == DamageCause.FALL) { //source.setCancelled(); return false; } else if (source.getCause() == DamageCause.FALL) { @@ -4418,6 +3953,29 @@ public boolean attack(EntityDamageEvent source) { } } + /** + * Drops an item on the ground in front of the player. Returns if the item drop was successful. + * + * @return bool if the item was dropped or if the item was null + */ + public boolean dropItem(Item item) { + if (!this.spawned || !this.isAlive()) { + return false; + } + + if (item.isNull()) { + this.server.getLogger().debug(this.getName() + " attempted to drop a null item (" + item + ")"); + return true; + } + + Vector3 motion = this.getDirectionVector().multiply(0.4); + + this.level.dropItem(this.add(0, 1.3, 0), item, motion, 40); + + this.setDataFlag(DATA_FLAGS, DATA_FLAG_ACTION, false); + return true; + } + public void sendPosition(Vector3 pos) { this.sendPosition(pos, this.yaw); } @@ -4430,11 +3988,11 @@ public void sendPosition(Vector3 pos, double yaw, double pitch) { this.sendPosition(pos, yaw, pitch, MovePlayerPacket.MODE_NORMAL); } - public void sendPosition(Vector3 pos, double yaw, double pitch, byte mode) { + public void sendPosition(Vector3 pos, double yaw, double pitch, int mode) { this.sendPosition(pos, yaw, pitch, mode, null); } - public void sendPosition(Vector3 pos, double yaw, double pitch, byte mode, Player[] targets) { + public void sendPosition(Vector3 pos, double yaw, double pitch, int mode, Player[] targets) { MovePlayerPacket pk = new MovePlayerPacket(); pk.eid = this.getId(); pk.x = (float) pos.x; @@ -4502,22 +4060,7 @@ protected boolean checkTeleportPosition() { } } - /*if (this.isLevelChange) { //TODO: remove this - PlayStatusPacket statusPacket0 = new PlayStatusPacket();//Weather - this.getLevel().sendWeather(this); - //Update time - this.getLevel().sendTime(this); - statusPacket0.status = PlayStatusPacket.PLAYER_SPAWN; - this.dataPacket(statusPacket0); - - //Weather - this.getLevel().sendWeather(this); - //Update time - this.getLevel().sendTime(this); - }*/ - this.spawnToAll(); - this.isLevelChange = false; this.forceMovement = this.teleportPosition; this.teleportPosition = null; return true; @@ -4526,7 +4069,20 @@ protected boolean checkTeleportPosition() { return false; } - private boolean isLevelChange = false; + protected void sendPlayStatus(int status) { + sendPlayStatus(status, false); + } + + protected void sendPlayStatus(int status, boolean immediate) { + PlayStatusPacket pk = new PlayStatusPacket(); + pk.status = status; + + if (immediate) { + this.directDataPacket(pk); + } else { + this.dataPacket(pk); + } + } @Override public boolean teleport(Location location, TeleportCause cause) { @@ -4553,18 +4109,13 @@ public boolean teleport(Location location, TeleportCause cause) { } } - if (super.teleport(to, null)) { // null to prevent fire of duplicate EntityTeleportEvent - - for (Inventory window : new ArrayList<>(this.windowIndex.values())) { - if (window == this.inventory) { - continue; - } - this.removeWindow(window); - } + //TODO Remove it! A hack to solve the client-side teleporting bug! (inside into the block) + if (super.teleport(to.getY() == to.getFloorY() ? to.add(0, 0.00001, 0) : to, null)) { // null to prevent fire of duplicate EntityTeleportEvent + this.removeAllWindows(); this.teleportPosition = new Vector3(this.x, this.y, this.z); this.forceMovement = this.teleportPosition; - this.sendPosition(this, this.yaw, this.pitch, MovePlayerPacket.MODE_RESET); + this.sendPosition(this, this.yaw, this.pitch, MovePlayerPacket.MODE_TELEPORT); this.checkTeleportPosition(); @@ -4572,42 +4123,12 @@ public boolean teleport(Location location, TeleportCause cause) { this.nextChunkOrderRun = 0; this.newPosition = null; + //DummyBossBar + this.getDummyBossBars().values().forEach(DummyBossBar::reshow); //Weather this.getLevel().sendWeather(this); //Update time this.getLevel().sendTime(this); - - if (from.getLevel().getId() != to.level.getId()) { - /*if (this.spawned) { //broken - //TODO: remove this in future version - this.isLevelChange = true; - this.nextChunkOrderRun = 10000; - - ChangeDimensionPacket changeDimensionPacket1 = new ChangeDimensionPacket(); - changeDimensionPacket1.dimension = 1; - changeDimensionPacket1.x = (float) this.getX(); - changeDimensionPacket1.y = (float) this.getY(); - changeDimensionPacket1.z = (float) this.getZ(); - this.dataPacket(changeDimensionPacket1); - - this.forceSendEmptyChunks(); - this.getServer().getScheduler().scheduleDelayedTask(() -> { - PlayStatusPacket statusPacket0 = new PlayStatusPacket(); - statusPacket0.status = PlayStatusPacket.PLAYER_SPAWN; - dataPacket(statusPacket0); - }, 8); - - this.getServer().getScheduler().scheduleDelayedTask(() -> { - ChangeDimensionPacket changeDimensionPacket = new ChangeDimensionPacket(); - changeDimensionPacket.dimension = 0; - changeDimensionPacket.x = (float) this.getX(); - changeDimensionPacket.y = (float) this.getY(); - changeDimensionPacket.z = (float) this.getZ(); - dataPacket(changeDimensionPacket); - nextChunkOrderRun = 0; - }, 9); - }*/ - } return true; } @@ -4668,103 +4189,107 @@ public void teleportImmediate(Location location, TeleportCause cause) { } } + /** + * Shows a new FormWindow to the player + * You can find out FormWindow result by listening to PlayerFormRespondedEvent + */ + public int showFormWindow(FormWindow window) { + int id = this.formWindowCount++; + + ModalFormRequestPacket packet = new ModalFormRequestPacket(); + packet.formId = id; + packet.data = window.getJSONData(); + this.formWindows.put(packet.formId, window); + + this.dataPacket(packet); + return id; + } + + /** + * Shows a new setting page in game settings + * You can find out settings result by listening to PlayerFormRespondedEvent + */ + public int addServerSettings(FormWindow window) { + int id = this.formWindowCount++; + + this.serverSettings.put(id, window); + return id; + } + /** * Creates and sends a BossBar to the player * - * @param text The BossBar message - * @param length The BossBar percentage + * @param text The BossBar message + * @param length The BossBar percentage * @return bossBarId The BossBar ID, you should store it if you want to remove or update the BossBar later */ + @Deprecated public long createBossBar(String text, int length) { - // First we spawn a entity - long bossBarId = 1095216660480L + ThreadLocalRandom.current().nextLong(0, 0x7fffffffL); - AddEntityPacket pkAdd = new AddEntityPacket(); - pkAdd.type = EntityCreeper.NETWORK_ID; - pkAdd.entityUniqueId = bossBarId; - pkAdd.entityRuntimeId = bossBarId; - pkAdd.x = (float) this.x; - pkAdd.y = (float) -10; // Below the bedrock - pkAdd.z = (float) this.z; - pkAdd.speedX = (float) this.motionX; - pkAdd.speedY = (float) this.motionY; - pkAdd.speedZ = (float) this.motionZ; - EntityMetadata metadata = new EntityMetadata() - // Default Metadata tags - .putLong(DATA_FLAGS, 0) - .putShort(DATA_AIR, 400) - .putShort(DATA_MAX_AIR, 400) - .putLong(DATA_LEAD_HOLDER_EID, -1) - .putFloat(DATA_SCALE, 1f) - .putString(Entity.DATA_NAMETAG, text) // Set the entity name - .putInt(Entity.DATA_SCALE, 0); // And make it invisible - pkAdd.metadata = metadata; - this.dataPacket(pkAdd); - - // Now we send the entity attributes - // TODO: Attributes should be sent on AddEntityPacket, however it doesn't work (client bug?) - UpdateAttributesPacket pkAttributes = new UpdateAttributesPacket(); - pkAttributes.entityId = bossBarId; - Attribute attr = Attribute.getAttribute(Attribute.MAX_HEALTH); - attr.setMaxValue(100); // Max value - We need to change the max value first, or else the "setValue" will return a IllegalArgumentException - attr.setValue(length); // Entity health - pkAttributes.entries = new Attribute[] { attr }; - this.dataPacket(pkAttributes); - - // And now we send the bossbar packet - BossEventPacket pkBoss = new BossEventPacket(); - pkBoss.eid = bossBarId; - pkBoss.type = BossEventPacket.ADD; - this.dataPacket(pkBoss); - return bossBarId; + DummyBossBar bossBar = new DummyBossBar.Builder(this).text(text).length(length).build(); + return this.createBossBar(bossBar); + } + + /** + * Creates and sends a BossBar to the player + * + * @param dummyBossBar DummyBossBar Object (Instantiate it by the Class Builder) + * @return bossBarId The BossBar ID, you should store it if you want to remove or update the BossBar later + * @see DummyBossBar.Builder + */ + public long createBossBar(DummyBossBar dummyBossBar) { + this.dummyBossBars.put(dummyBossBar.getBossBarId(), dummyBossBar); + dummyBossBar.create(); + return dummyBossBar.getBossBarId(); + } + + /** + * Get a DummyBossBar object + * + * @param bossBarId The BossBar ID + * @return DummyBossBar object + * @see DummyBossBar#setText(String) Set BossBar text + * @see DummyBossBar#setLength(float) Set BossBar length + * @see DummyBossBar#setColor(Color) Set BossBar color + */ + public DummyBossBar getDummyBossBar(long bossBarId) { + return this.dummyBossBars.getOrDefault(bossBarId, null); + } + + /** + * Get all DummyBossBar objects + * + * @return DummyBossBars Map + */ + public Map getDummyBossBars() { + return dummyBossBars; } /** * Updates a BossBar * - * @param text The new BossBar message - * @param length The new BossBar length - * @param bossBarId The BossBar ID + * @param text The new BossBar message + * @param length The new BossBar length + * @param bossBarId The BossBar ID */ + @Deprecated public void updateBossBar(String text, int length, long bossBarId) { - // First we update the boss bar length - UpdateAttributesPacket pkAttributes = new UpdateAttributesPacket(); - pkAttributes.entityId = bossBarId; - Attribute attr = Attribute.getAttribute(Attribute.MAX_HEALTH); - attr.setMaxValue(100); // Max value - We need to change the max value first, or else the "setValue" will return a IllegalArgumentException - attr.setValue(length); // Entity health - pkAttributes.entries = new Attribute[] { attr }; - this.dataPacket(pkAttributes); - // And then the boss bar text - SetEntityDataPacket pkMetadata = new SetEntityDataPacket(); - pkMetadata.eid = bossBarId; - pkMetadata.metadata = new EntityMetadata() - // Default Metadata tags - .putLong(DATA_FLAGS, 0) - .putShort(DATA_AIR, 400) - .putShort(DATA_MAX_AIR, 400) - .putLong(DATA_LEAD_HOLDER_EID, -1) - .putFloat(DATA_SCALE, 1f) - .putString(Entity.DATA_NAMETAG, text) // Set the entity name - .putInt(Entity.DATA_SCALE, 0); // And make it invisible - this.dataPacket(pkMetadata); - - // And now we send the bossbar packet - BossEventPacket pkBoss = new BossEventPacket(); - pkBoss.eid = bossBarId; - pkBoss.type = BossEventPacket.UPDATE; - this.dataPacket(pkBoss); - return; + if (this.dummyBossBars.containsKey(bossBarId)) { + DummyBossBar bossBar = this.dummyBossBars.get(bossBarId); + bossBar.setText(text); + bossBar.setLength(length); + } } /** * Removes a BossBar * - * @param bossBarId The BossBar ID + * @param bossBarId The BossBar ID */ public void removeBossBar(long bossBarId) { - RemoveEntityPacket pkRemove = new RemoveEntityPacket(); - pkRemove.eid = bossBarId; - this.dataPacket(pkRemove); + if (this.dummyBossBars.containsKey(bossBarId)) { + this.dummyBossBars.get(bossBarId).destroy(); + this.dummyBossBars.remove(bossBarId); + } } public int getWindowId(Inventory inventory) { @@ -4775,22 +4300,35 @@ public int getWindowId(Inventory inventory) { return -1; } + public Inventory getWindowById(int id) { + return this.windowIndex.get(id); + } + public int addWindow(Inventory inventory) { return this.addWindow(inventory, null); } public int addWindow(Inventory inventory, Integer forceId) { + return addWindow(inventory, forceId, false); + } + + public int addWindow(Inventory inventory, Integer forceId, boolean isPermanent) { if (this.windows.containsKey(inventory)) { return this.windows.get(inventory); } int cnt; if (forceId == null) { - this.windowCnt = cnt = Math.max(2, ++this.windowCnt % 99); + this.windowCnt = cnt = Math.max(4, ++this.windowCnt % 99); } else { cnt = forceId; } this.windowIndex.put(cnt, inventory); this.windows.put(inventory, cnt); + + if (isPermanent) { + this.permanentWindows.add(cnt); + } + if (inventory.open(this)) { return cnt; } else { @@ -4809,6 +4347,65 @@ public void removeWindow(Inventory inventory) { } } + public void sendAllInventories() { + for (Inventory inv : this.windowIndex.values()) { + inv.sendContents(this); + + if (inv instanceof PlayerInventory) { + ((PlayerInventory) inv).sendArmorContents(this); + } + } + } + + protected void addDefaultWindows() { + this.addWindow(this.getInventory(), ContainerIds.INVENTORY, true); + + this.cursorInventory = new PlayerCursorInventory(this); + this.addWindow(this.cursorInventory, ContainerIds.CURSOR, true); + + this.craftingGrid = new CraftingGrid(this); + + //TODO: more windows + } + + public PlayerCursorInventory getCursorInventory() { + return this.cursorInventory; + } + + public CraftingGrid getCraftingGrid() { + return this.craftingGrid; + } + + public void setCraftingGrid(CraftingGrid grid) { + this.craftingGrid = grid; + } + + public void resetCraftingGridType() { + if (this.craftingGrid instanceof BigCraftingGrid) { + Item[] drops = this.inventory.addItem(this.craftingGrid.getContents().values().stream().toArray(Item[]::new)); + for (Item drop : drops) { + this.dropItem(drop); + } + + this.craftingGrid = new CraftingGrid(this); + this.craftingType = 0; + } + } + + public void removeAllWindows() { + removeAllWindows(false); + } + + public void removeAllWindows(boolean permanent) { + for (Entry entry : new ArrayList<>(this.windowIndex.entrySet())) { + if (!permanent && this.permanentWindows.contains(entry.getKey())) { + continue; + } + + this.removeWindow(entry.getValue()); + } + } + @Override public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { this.server.getPlayerMetadata().setMetadata(this, metadataKey, newMetadataValue); @@ -4943,12 +4540,12 @@ public void transfer(InetSocketAddress address) { this.close(message, message, false); } - public ClientChainData getLoginChainData() { + public LoginChainData getLoginChainData() { return this.loginChainData; } public boolean pickupEntity(Entity entity, boolean near) { - if (!this.spawned || !this.isAlive() || !this.isOnline()) { + if (!this.spawned || !this.isAlive() || !this.isOnline() || this.getGamemode() == SPECTATOR) { return false; } @@ -4969,10 +4566,6 @@ public boolean pickupEntity(Entity entity, boolean near) { pk.entityId = this.getId(); pk.target = entity.getId(); Server.broadcastPacket(entity.getViewers().values(), pk); - - pk = new TakeItemEntityPacket(); - pk.entityId = this.id; - pk.target = entity.getId(); this.dataPacket(pk); this.inventory.addItem(item.clone()); @@ -5015,10 +4608,6 @@ public boolean pickupEntity(Entity entity, boolean near) { pk.entityId = this.getId(); pk.target = entity.getId(); Server.broadcastPacket(entity.getViewers().values(), pk); - - pk = new TakeItemEntityPacket(); - pk.entityId = this.id; - pk.target = entity.getId(); this.dataPacket(pk); this.inventory.addItem(item.clone()); @@ -5071,4 +4660,18 @@ public boolean equals(Object obj) { public void notifyACK(int identification) { needACK.put(identification, true); } + + public boolean isBreakingBlock() { + return this.breakingBlock != null; + } + + /** + * Show a window of a XBOX account's profile + * @param xuid XUID + */ + public void showXboxProfile(String xuid) { + ShowProfilePacket pk = new ShowProfilePacket(); + pk.xuid = xuid; + this.dataPacket(pk); + } } diff --git a/src/main/java/cn/nukkit/PlayerFood.java b/src/main/java/cn/nukkit/PlayerFood.java index 9ab78ac94e..166ba513b4 100644 --- a/src/main/java/cn/nukkit/PlayerFood.java +++ b/src/main/java/cn/nukkit/PlayerFood.java @@ -136,37 +136,37 @@ public void sendFoodLevel(int foodLevel) { public void update(int tickDiff) { if (!this.getPlayer().isFoodEnabled()) return; - if (this.getPlayer().isAlive()) { - int diff = Server.getInstance().getDifficulty(); - if (this.getLevel() > 17) { - this.foodTickTimer += tickDiff; - if (this.foodTickTimer >= 80) { - if (this.getPlayer().getHealth() < this.getPlayer().getMaxHealth()) { - EntityRegainHealthEvent ev = new EntityRegainHealthEvent(this.getPlayer(), 1, EntityRegainHealthEvent.CAUSE_EATING); - this.getPlayer().heal(ev); - //this.updateFoodExpLevel(3); - } - this.foodTickTimer = 0; - } - } else if (this.getLevel() == 0) { - this.foodTickTimer += tickDiff; - if (this.foodTickTimer >= 80) { - EntityDamageEvent ev = new EntityDamageEvent(this.getPlayer(), DamageCause.VOID, 1); - float now = this.getPlayer().getHealth(); - if (diff == 1) { - if (now > 10) this.getPlayer().attack(ev); - } else if (diff == 2) { - if (now > 1) this.getPlayer().attack(ev); - } else { - this.getPlayer().attack(ev); - } - - this.foodTickTimer = 0; - } - } - if (this.getPlayer().hasEffect(Effect.HUNGER)) { - this.updateFoodExpLevel(0.025); - } + if (this.getPlayer().isAlive()) { + int diff = Server.getInstance().getDifficulty(); + if (this.getLevel() > 17) { + this.foodTickTimer += tickDiff; + if (this.foodTickTimer >= 80) { + if (this.getPlayer().getHealth() < this.getPlayer().getMaxHealth()) { + EntityRegainHealthEvent ev = new EntityRegainHealthEvent(this.getPlayer(), 1, EntityRegainHealthEvent.CAUSE_EATING); + this.getPlayer().heal(ev); + //this.updateFoodExpLevel(3); + } + this.foodTickTimer = 0; + } + } else if (this.getLevel() == 0) { + this.foodTickTimer += tickDiff; + if (this.foodTickTimer >= 80) { + EntityDamageEvent ev = new EntityDamageEvent(this.getPlayer(), DamageCause.VOID, 1); + float now = this.getPlayer().getHealth(); + if (diff == 1) { + if (now > 10) this.getPlayer().attack(ev); + } else if (diff == 2) { + if (now > 1) this.getPlayer().attack(ev); + } else { + this.getPlayer().attack(ev); + } + + this.foodTickTimer = 0; + } + } + if (this.getPlayer().hasEffect(Effect.HUNGER)) { + this.updateFoodExpLevel(0.025); + } } } diff --git a/src/main/java/cn/nukkit/Server.java b/src/main/java/cn/nukkit/Server.java index 81add9a976..af8b134427 100644 --- a/src/main/java/cn/nukkit/Server.java +++ b/src/main/java/cn/nukkit/Server.java @@ -11,6 +11,7 @@ import cn.nukkit.entity.mob.*; import cn.nukkit.entity.passive.*; import cn.nukkit.entity.projectile.EntityArrow; +import cn.nukkit.entity.projectile.EntityEgg; import cn.nukkit.entity.projectile.EntityEnderPearl; import cn.nukkit.entity.projectile.EntitySnowball; import cn.nukkit.event.HandlerList; @@ -263,6 +264,7 @@ public class Server { this.properties = new Config(this.dataPath + "server.properties", Config.PROPERTIES, new ConfigSection() { { put("motd", "Nukkit Server For Minecraft: PE"); + put("sub-motd", "Powered by Nukkit"); put("server-port", 19132); put("server-ip", "0.0.0.0"); put("view-distance", 10); @@ -357,6 +359,7 @@ public class Server { this.network = new Network(this); this.network.setName(this.getMotd()); + this.network.setSubName(this.getSubMotd()); this.logger.info(this.getLanguage().translateString("nukkit.server.info", this.getName(), TextFormat.YELLOW + this.getNukkitVersion() + TextFormat.WHITE, TextFormat.AQUA + this.getCodename() + TextFormat.WHITE, this.getApiVersion())); this.logger.info(this.getLanguage().translateString("nukkit.server.license", this.getName())); @@ -430,7 +433,7 @@ public class Server { if (this.getDefaultLevel() == null) { String defaultName = this.getPropertyString("level-name", "world"); - if (defaultName == null || "".equals(defaultName.trim())) { + if (defaultName == null || defaultName.trim().isEmpty()) { this.getLogger().warning("level-name cannot be null, using default"); defaultName = "world"; this.setPropertyString("level-name", defaultName); @@ -643,7 +646,7 @@ public boolean dispatchCommand(CommandSender sender, String commandLine) throws return true; } - sender.sendMessage(new TranslationContainer(TextFormat.RED + "%commands.generic.notFound")); + sender.sendMessage(new TranslationContainer(TextFormat.RED + "%commands.generic.unknown", commandLine)); return false; } @@ -814,6 +817,10 @@ public void tickProcessor() { } } + public void onPlayerCompleteLoginSequence(Player player) { + this.sendFullPlayerListData(player); + } + public void onPlayerLogin(Player player) { if (this.sendUsageTicker > 0) { this.uniquePlayers.add(player.getUniqueId()); @@ -827,7 +834,7 @@ public void addPlayer(String identifier, Player player) { public void addOnlinePlayer(Player player) { this.playerList.put(player.getUniqueId(), player); - this.updatePlayerListData(player.getUniqueId(), player.getId(), player.getDisplayName(), player.getSkin()); + this.updatePlayerListData(player.getUniqueId(), player.getId(), player.getDisplayName(), player.getSkin(), player.getLoginChainData().getXUID()); } public void removeOnlinePlayer(Player player) { @@ -843,18 +850,26 @@ public void removeOnlinePlayer(Player player) { } public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin) { - this.updatePlayerListData(uuid, entityId, name, skin, this.playerList.values()); + this.updatePlayerListData(uuid, entityId, name, skin, "", this.playerList.values()); + } + + public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, String xboxUserId) { + this.updatePlayerListData(uuid, entityId, name, skin, xboxUserId, this.playerList.values()); } public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, Player[] players) { + this.updatePlayerListData(uuid, entityId, name, skin, "", players); + } + + public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, String xboxUserId, Player[] players) { PlayerListPacket pk = new PlayerListPacket(); pk.type = PlayerListPacket.TYPE_ADD; - pk.entries = new PlayerListPacket.Entry[]{new PlayerListPacket.Entry(uuid, entityId, name, skin)}; + pk.entries = new PlayerListPacket.Entry[]{new PlayerListPacket.Entry(uuid, entityId, name, skin, xboxUserId)}; Server.broadcastPacket(players, pk); } - public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, Collection players) { - this.updatePlayerListData(uuid, entityId, name, skin, + public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, String xboxUserId, Collection players) { + this.updatePlayerListData(uuid, entityId, name, skin, xboxUserId, players.stream() .filter(p -> !p.getUniqueId().equals(uuid)) .toArray(Player[]::new)); @@ -876,17 +891,15 @@ public void removePlayerListData(UUID uuid, Collection players) { } public void sendFullPlayerListData(Player player) { - final UUID uuid = player.getUniqueId(); PlayerListPacket pk = new PlayerListPacket(); pk.type = PlayerListPacket.TYPE_ADD; - pk.entries = this.playerList.values() - .stream() - .filter(p -> !p.getUniqueId().equals(uuid)) + pk.entries = this.playerList.values().stream() .map(p -> new PlayerListPacket.Entry( p.getUniqueId(), p.getId(), p.getDisplayName(), - p.getSkin())) + p.getSkin(), + p.getLoginChainData().getXUID())) .toArray(PlayerListPacket.Entry[]::new); player.dataPacket(pk); @@ -1001,6 +1014,7 @@ private boolean tick() { if ((this.tickCounter & 0b1111) == 0) { this.titleTick(); + this.network.resetStatistics(); this.maxTick = 20; this.maxUse = 0; @@ -1069,7 +1083,7 @@ private boolean tick() { // TODO: Fix title tick public void titleTick() { - if (true || !Nukkit.ANSI) { + if (!Nukkit.ANSI) { return; } @@ -1089,8 +1103,6 @@ public void titleTick() { " | Load " + this.getTickUsage() + "%" + (char) 0x07; System.out.print(title); - - this.network.resetStatistics(); } public QueryRegenerateEvent getQueryInformation() { @@ -1181,15 +1193,19 @@ public boolean getForceGamemode() { } public static String getGamemodeString(int mode) { + return getGamemodeString(mode, false); + } + + public static String getGamemodeString(int mode, boolean direct) { switch (mode) { case Player.SURVIVAL: - return "%gameMode.survival"; + return direct ? "Survival" : "%gameMode.survival"; case Player.CREATIVE: - return "%gameMode.creative"; + return direct ? "Creative" : "%gameMode.creative"; case Player.ADVENTURE: - return "%gameMode.adventure"; + return direct ? "Adventure" : "%gameMode.adventure"; case Player.SPECTATOR: - return "%gameMode.spectator"; + return direct ? "Spectator" : "%gameMode.spectator"; } return "UNKNOWN"; } @@ -1277,6 +1293,10 @@ public String getMotd() { return this.getPropertyString("motd", "Nukkit Server For Minecraft: PE"); } + public String getSubMotd() { + return this.getPropertyString("sub-motd", "Powered by Nukkit"); + } + public boolean getForceResources() { return this.getPropertyBoolean("force-resources", false); } @@ -1891,8 +1911,9 @@ public boolean shouldSavePlayerData() { /** * Checks the current thread against the expected primary thread for the server. - * + *

* Note: this method should not be used to indicate the current synchronized state of the runtime. A current thread matching the main thread indicates that it is synchronized, but a mismatch does not preclude the same assumption. + * * @return true if the current thread matches the expected primary thread, false otherwise */ public boolean isPrimaryThread() { @@ -1949,6 +1970,7 @@ private void registerEntities() { Entity.registerEntity("ThrownExpBottle", EntityExpBottle.class); Entity.registerEntity("XpOrb", EntityXPOrb.class); Entity.registerEntity("ThrownPotion", EntityPotion.class); + Entity.registerEntity("Egg", EntityEgg.class); Entity.registerEntity("Human", EntityHuman.class, true); @@ -1975,6 +1997,7 @@ private void registerBlockEntities() { BlockEntity.registerBlockEntity(BlockEntity.COMPARATOR, BlockEntityComparator.class); BlockEntity.registerBlockEntity(BlockEntity.HOPPER, BlockEntityHopper.class); BlockEntity.registerBlockEntity(BlockEntity.BED, BlockEntityBed.class); + BlockEntity.registerBlockEntity(BlockEntity.JUKEBOX, BlockEntityJukebox.class); } public static Server getInstance() { diff --git a/src/main/java/cn/nukkit/api/API.java b/src/main/java/cn/nukkit/api/API.java index e906d2b0b0..70f7369ecc 100644 --- a/src/main/java/cn/nukkit/api/API.java +++ b/src/main/java/cn/nukkit/api/API.java @@ -11,9 +11,9 @@ /** * Describes an API element. * + * @author Lin Mulan, Nukkit Project * @see Usage * @see Definition - * @author Lin Mulan, Nukkit Project */ @Retention(RetentionPolicy.SOURCE) @Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE}) @@ -21,110 +21,110 @@ @SuppressWarnings("unused") public @interface API { - /** - * Indicates the level of stability of an API element. - * The stability also describes when to use this API element. - * - * @return The stability - * @see Usage - */ - Usage usage(); - - /** - * Indicates definition or the platforms this API element supports. - * - * @return The definition - * @see Definition - */ - Definition definition(); - - /** - * Enum constant for API usage. Indicates when to use this API element. - * - * @see #DEPRECATED - * @see #INCUBATING - * @see #BLEEDING - * @see #EXPERIMENTAL - * @see #MAINTAINED - * @see #STABLE - */ - enum Usage{ - - /** - * Should no longer be used, might disappear in the next minor release. - */ - DEPRECATED, - /** - * Intended for features in drafts. Should only be used for tests. + * Indicates the level of stability of an API element. + * The stability also describes when to use this API element. * - *

Might contains notable new features, but will be moved to a new package before remarking to {@link #BLEEDING}. - * Could be unsafe, might be removed without prior notice. Warnings will be send if used. + * @return The stability + * @see Usage */ - INCUBATING, + Usage usage(); /** - * Intended for features in early development. Should only be used for tests. + * Indicates definition or the platforms this API element supports. * - *

Might be unwrapped, unsafe or have unchecked parameters. - * Further contribution was demanded to enhance, strengthen or simplify before remarking to {@link #EXPERIMENTAL}. - * Might be removed or modified without prior notice. - */ - BLEEDING, - - /** - * Intended for new, experimental features where we are looking for feedback. - * At least stable for development. - * - *

Use with caution, might be remarked to {@link #MAINTAINED} or {@link #STABLE} in the future, - * but also might be removed without prior notice. - */ - EXPERIMENTAL, - - /** - * Intended for features that was tested, documented and at least stable for production use. - * - *

These features will not be modified in a backwards-incompatible way for at least next minor release - * of the current major version. Will be remarked to {@link #DEPRECATED} first if scheduled for removal. - */ - MAINTAINED, - - /** - * Intended for features that was tested, documented and is preferred in production use. - * - *

Will not be changed in a backwards-incompatible way in the current version. - */ - STABLE - } - - /** - * Enum constant for API definition. Indicates which client platform this API element supports. - * - * @see #INTERNAL - * @see #PLATFORM_NATIVE - * @see #UNIVERSAL - */ - enum Definition{ - - /** - * Intended for features should only be used by Nukkit itself. - * Should not be used in production. + * @return The definition + * @see Definition */ - INTERNAL, + Definition definition(); /** - * Intended for features only available on one or several client platforms. + * Enum constant for API usage. Indicates when to use this API element. * - *

By using {@code PLATFORM_NATIVE} features, program will lose some cross-platform features provided. - * Might not available in some client platforms. Read the documents carefully before using this API element. + * @see #DEPRECATED + * @see #INCUBATING + * @see #BLEEDING + * @see #EXPERIMENTAL + * @see #MAINTAINED + * @see #STABLE */ - PLATFORM_NATIVE, + enum Usage { + + /** + * Should no longer be used, might disappear in the next minor release. + */ + DEPRECATED, + + /** + * Intended for features in drafts. Should only be used for tests. + *

+ *

Might contains notable new features, but will be moved to a new package before remarking to {@link #BLEEDING}. + * Could be unsafe, might be removed without prior notice. Warnings will be send if used. + */ + INCUBATING, + + /** + * Intended for features in early development. Should only be used for tests. + *

+ *

Might be unwrapped, unsafe or have unchecked parameters. + * Further contribution was demanded to enhance, strengthen or simplify before remarking to {@link #EXPERIMENTAL}. + * Might be removed or modified without prior notice. + */ + BLEEDING, + + /** + * Intended for new, experimental features where we are looking for feedback. + * At least stable for development. + *

+ *

Use with caution, might be remarked to {@link #MAINTAINED} or {@link #STABLE} in the future, + * but also might be removed without prior notice. + */ + EXPERIMENTAL, + + /** + * Intended for features that was tested, documented and at least stable for production use. + *

+ *

These features will not be modified in a backwards-incompatible way for at least next minor release + * of the current major version. Will be remarked to {@link #DEPRECATED} first if scheduled for removal. + */ + MAINTAINED, + + /** + * Intended for features that was tested, documented and is preferred in production use. + *

+ *

Will not be changed in a backwards-incompatible way in the current version. + */ + STABLE + } /** - * Intended for features implemented in all client platforms. + * Enum constant for API definition. Indicates which client platform this API element supports. * - *

Preferred to use for production use, but sometimes be lack of platform-native features. + * @see #INTERNAL + * @see #PLATFORM_NATIVE + * @see #UNIVERSAL */ - UNIVERSAL - } + enum Definition { + + /** + * Intended for features should only be used by Nukkit itself. + * Should not be used in production. + */ + INTERNAL, + + /** + * Intended for features only available on one or several client platforms. + *

+ *

By using {@code PLATFORM_NATIVE} features, program will lose some cross-platform features provided. + * Might not available in some client platforms. Read the documents carefully before using this API element. + */ + PLATFORM_NATIVE, + + /** + * Intended for features implemented in all client platforms. + *

+ *

Preferred to use for production use, but sometimes be lack of platform-native features. + */ + UNIVERSAL + } } diff --git a/src/main/java/cn/nukkit/block/Block.java b/src/main/java/cn/nukkit/block/Block.java index be476fac00..de6230759d 100644 --- a/src/main/java/cn/nukkit/block/Block.java +++ b/src/main/java/cn/nukkit/block/Block.java @@ -141,7 +141,7 @@ public abstract class Block extends Position implements Metadatable, Cloneable { public static final int CLAY_BLOCK = 82; public static final int REEDS = 83; public static final int SUGARCANE_BLOCK = 83; - + public static final int JUKEBOX = 84; public static final int FENCE = 85; public static final int PUMPKIN = 86; public static final int NETHERRACK = 87; @@ -295,6 +295,11 @@ public abstract class Block extends Position implements Metadatable, Cloneable { public static final int END_ROD = 208; public static final int END_GATEWAY = 209; + public static final int MAGMA = 213; + public static final int BLOCK_NETHER_WART_BLOCK = 214; + public static final int RED_NETHER_BRICK = 215; + public static final int BONE_BLOCK = 216; + public static final int SHULKER_BOX = 218; public static final int PURPLE_GLAZED_TERRACOTTA = 219; public static final int WHITE_GLAZED_TERRACOTTA = 220; @@ -410,7 +415,7 @@ public static void init() { list[REDSTONE_WIRE] = BlockRedstoneWire.class; //55 list[DIAMOND_ORE] = BlockOreDiamond.class; //56 list[DIAMOND_BLOCK] = BlockDiamond.class; //57 - list[WORKBENCH] = BlockWorkbench.class; //58 + list[WORKBENCH] = BlockCraftingTable.class; //58 list[WHEAT_BLOCK] = BlockWheat.class; //59 list[FARMLAND] = BlockFarmland.class; //60 list[FURNACE] = BlockFurnace.class; //61 @@ -436,7 +441,7 @@ public static void init() { list[CACTUS] = BlockCactus.class; //81 list[CLAY_BLOCK] = BlockClay.class; //82 list[SUGARCANE_BLOCK] = BlockSugarcane.class; //83 - + list[JUKEBOX] = BlockJukebox.class; //84 list[FENCE] = BlockFence.class; //85 list[PUMPKIN] = BlockPumpkin.class; //86 list[NETHERRACK] = BlockNetherrack.class; //87 @@ -512,7 +517,7 @@ public static void init() { list[DOUBLE_WOOD_SLAB] = BlockDoubleSlabWood.class; //157 list[WOOD_SLAB] = BlockSlabWood.class; //158 list[STAINED_TERRACOTTA] = BlockTerracottaStained.class; //159 - //TODO: list[STAINED_GLASS_PANE] = BlockGlassPaneStained.class; //160 + list[STAINED_GLASS_PANE] = BlockGlassPaneStained.class; //160 list[LEAVES2] = BlockLeaves2.class; //161 list[WOOD2] = BlockWood2.class; //162 @@ -558,6 +563,8 @@ public static void init() { list[END_ROD] = BlockEndRod.class; //208 list[END_GATEWAY] = BlockEndGateway.class; //209 + list[BONE_BLOCK] = BlockBone.class; //216 + //TODO: list[SHULKER_BOX] = BlockShulkerBox.class; //218 list[PURPLE_GLAZED_TERRACOTTA] = BlockTerracottaGlazedPurple.class; //219 list[WHITE_GLAZED_TERRACOTTA] = BlockTerracottaGlazedWhite.class; //220 @@ -580,6 +587,7 @@ public static void init() { list[CONCRETE_POWDER] = BlockConcretePowder.class; //237 //TODO: list[CHORUS_PLANT] = BlockChorusPlant.class; //240 + list[STAINED_GLASS] = BlockGlassStained.class; //241 list[PODZOL] = BlockPodzol.class; //243 list[BEETROOT_BLOCK] = BlockBeetroot.class; //244 list[GLOWING_OBSIDIAN] = BlockObsidianGlowing.class; //246 @@ -822,21 +830,27 @@ public Item[] getDrops(Item item) { private static double toolBreakTimeBonus0( int toolType, int toolTier, boolean isWoolBlock, boolean isCobweb) { - if(toolType == ItemTool.TYPE_SWORD) return isCobweb ? 15.0: 1.0; - if(toolType == ItemTool.TYPE_SHEARS) return isWoolBlock ? 5.0: 15.0; - if(toolType == ItemTool.TYPE_NONE) return 1.0; + if (toolType == ItemTool.TYPE_SWORD) return isCobweb ? 15.0 : 1.0; + if (toolType == ItemTool.TYPE_SHEARS) return isWoolBlock ? 5.0 : 15.0; + if (toolType == ItemTool.TYPE_NONE) return 1.0; switch (toolTier) { - case ItemTool.TIER_WOODEN: return 2.0; - case ItemTool.TIER_STONE: return 4.0; - case ItemTool.TIER_IRON: return 6.0; - case ItemTool.TIER_DIAMOND: return 8.0; - case ItemTool.TIER_GOLD: return 12.0; - default: return 1.0; + case ItemTool.TIER_WOODEN: + return 2.0; + case ItemTool.TIER_STONE: + return 4.0; + case ItemTool.TIER_IRON: + return 6.0; + case ItemTool.TIER_DIAMOND: + return 8.0; + case ItemTool.TIER_GOLD: + return 12.0; + default: + return 1.0; } } private static double speedBonusByEfficiencyLore0(int efficiencyLoreLevel) { - if(efficiencyLoreLevel == 0) return 0; + if (efficiencyLoreLevel == 0) return 0; return efficiencyLoreLevel * efficiencyLoreLevel + 1; } @@ -845,20 +859,20 @@ private static double speedRateByHasteLore0(int hasteLoreLevel) { } private static int toolType0(Item item) { - if(item.isSword()) return ItemTool.TYPE_SWORD ; - if(item.isShovel()) return ItemTool.TYPE_SHOVEL ; - if(item.isPickaxe()) return ItemTool.TYPE_PICKAXE ; - if(item.isAxe()) return ItemTool.TYPE_AXE ; - if(item.isShears()) return ItemTool.TYPE_SHEARS ; + if (item.isSword()) return ItemTool.TYPE_SWORD; + if (item.isShovel()) return ItemTool.TYPE_SHOVEL; + if (item.isPickaxe()) return ItemTool.TYPE_PICKAXE; + if (item.isAxe()) return ItemTool.TYPE_AXE; + if (item.isShears()) return ItemTool.TYPE_SHEARS; return ItemTool.TYPE_NONE; } private static boolean correctTool0(int blockToolType, Item item) { - return (blockToolType == ItemTool.TYPE_SWORD && item.isSword() ) || - (blockToolType == ItemTool.TYPE_SHOVEL && item.isShovel() ) || - (blockToolType == ItemTool.TYPE_PICKAXE && item.isPickaxe() ) || - (blockToolType == ItemTool.TYPE_AXE && item.isAxe() ) || - (blockToolType == ItemTool.TYPE_SHEARS && item.isShears() ) || + return (blockToolType == ItemTool.TYPE_SWORD && item.isSword()) || + (blockToolType == ItemTool.TYPE_SHOVEL && item.isShovel()) || + (blockToolType == ItemTool.TYPE_PICKAXE && item.isPickaxe()) || + (blockToolType == ItemTool.TYPE_AXE && item.isAxe()) || + (blockToolType == ItemTool.TYPE_SHEARS && item.isShears()) || blockToolType == ItemTool.TYPE_NONE; } @@ -869,11 +883,11 @@ private static double breakTime0(double blockHardness, boolean correctTool, bool double baseTime = ((correctTool || canHarvestWithHand) ? 1.5 : 5.0) * blockHardness; double speed = 1.0 / baseTime; boolean isWoolBlock = blockId == Block.WOOL, isCobweb = blockId == Block.COBWEB; - if(correctTool) speed *= toolBreakTimeBonus0(toolType, toolTier, isWoolBlock, isCobweb); + if (correctTool) speed *= toolBreakTimeBonus0(toolType, toolTier, isWoolBlock, isCobweb); speed += speedBonusByEfficiencyLore0(efficiencyLoreLevel); speed *= speedRateByHasteLore0(hasteEffectLevel); - if(insideOfWaterWithoutAquaAffinity) speed *= 0.2; - if(outOfWaterButNotOnGround) speed *= 0.2; + if (insideOfWaterWithoutAquaAffinity) speed *= 0.2; + if (outOfWaterButNotOnGround) speed *= 0.2; return 1.0 / speed; } diff --git a/src/main/java/cn/nukkit/block/BlockAnvil.java b/src/main/java/cn/nukkit/block/BlockAnvil.java index 7759da99e6..d8a60a5d5a 100644 --- a/src/main/java/cn/nukkit/block/BlockAnvil.java +++ b/src/main/java/cn/nukkit/block/BlockAnvil.java @@ -76,9 +76,9 @@ public boolean place(Item item, Block block, Block target, BlockFace face, doubl int[] faces = {1, 2, 3, 0}; this.meta = faces[player != null ? player.getDirection().getHorizontalIndex() : 0]; if (damage >= 4 && damage <= 7) { - this.meta |= 0x04; + this.meta |= 0x04; } else if (damage >= 8 && damage <= 11) { - this.meta |= 0x08; + this.meta |= 0x08; } this.getLevel().setBlock(block, this, true); return true; @@ -89,7 +89,7 @@ public boolean place(Item item, Block block, Block target, BlockFace face, doubl @Override public boolean onActivate(Item item, Player player) { if (player != null) { - player.addWindow(new AnvilInventory(this)); + player.addWindow(new AnvilInventory(this), Player.ANVIL_WINDOW_ID); } return true; } diff --git a/src/main/java/cn/nukkit/block/BlockBed.java b/src/main/java/cn/nukkit/block/BlockBed.java index 72ffe14a2a..6f84f2bf02 100644 --- a/src/main/java/cn/nukkit/block/BlockBed.java +++ b/src/main/java/cn/nukkit/block/BlockBed.java @@ -5,6 +5,7 @@ import cn.nukkit.blockentity.BlockEntityBed; import cn.nukkit.item.Item; import cn.nukkit.item.ItemBed; +import cn.nukkit.lang.TranslationContainer; import cn.nukkit.level.Level; import cn.nukkit.math.AxisAlignedBB; import cn.nukkit.math.BlockFace; @@ -77,7 +78,7 @@ public boolean onActivate(Item item, Player player) { boolean isNight = (time >= Level.TIME_NIGHT && time < Level.TIME_SUNRISE); if (player != null && !isNight) { - player.sendMessage(TextFormat.GRAY + "You can only sleep at night"); + player.sendMessage(new TranslationContainer("tile.bed.noSleep")); return true; } @@ -100,7 +101,7 @@ public boolean onActivate(Item item, Player player) { b = blockWest; } else { if (player != null) { - player.sendMessage(TextFormat.GRAY + "This bed is incomplete"); + player.sendMessage(new TranslationContainer("tile.bed.notValid")); } return true; @@ -108,7 +109,7 @@ public boolean onActivate(Item item, Player player) { } if (player != null && !player.sleepOn(b)) { - player.sendMessage(TextFormat.GRAY + "This bed is occupied"); + player.sendMessage(new TranslationContainer("tile.bed.occupied")); } diff --git a/src/main/java/cn/nukkit/block/BlockBone.java b/src/main/java/cn/nukkit/block/BlockBone.java new file mode 100644 index 0000000000..4e28539b40 --- /dev/null +++ b/src/main/java/cn/nukkit/block/BlockBone.java @@ -0,0 +1,53 @@ +package cn.nukkit.block; + +import cn.nukkit.item.Item; +import cn.nukkit.item.ItemBlock; +import cn.nukkit.item.ItemTool; + +/** + * @author CreeperFace + */ +public class BlockBone extends BlockSolid { + + public BlockBone() { + this(0); + } + + public BlockBone(int meta) { + super(meta); + } + + @Override + public int getId() { + return BONE_BLOCK; + } + + @Override + public String getName() { + return "Bone Block"; + } + + @Override + public double getHardness() { + return 2; + } + + @Override + public double getResistance() { + return 10; + } + + @Override + public int getToolType() { + return ItemTool.TYPE_PICKAXE; + } + + @Override + public Item[] getDrops(Item item) { + if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_WOODEN) { + return new Item[]{new ItemBlock(this)}; + } + + return new Item[0]; + } +} diff --git a/src/main/java/cn/nukkit/block/BlockWorkbench.java b/src/main/java/cn/nukkit/block/BlockCraftingTable.java similarity index 81% rename from src/main/java/cn/nukkit/block/BlockWorkbench.java rename to src/main/java/cn/nukkit/block/BlockCraftingTable.java index b5129f79f4..c94c41ca39 100644 --- a/src/main/java/cn/nukkit/block/BlockWorkbench.java +++ b/src/main/java/cn/nukkit/block/BlockCraftingTable.java @@ -1,6 +1,7 @@ package cn.nukkit.block; import cn.nukkit.Player; +import cn.nukkit.inventory.BigCraftingGrid; import cn.nukkit.item.Item; import cn.nukkit.item.ItemTool; import cn.nukkit.utils.BlockColor; @@ -9,12 +10,12 @@ * Created on 2015/12/5 by xtypr. * Package cn.nukkit.block in project Nukkit . */ -public class BlockWorkbench extends BlockSolid { - public BlockWorkbench() { +public class BlockCraftingTable extends BlockSolid { + public BlockCraftingTable() { this(0); } - public BlockWorkbench(int meta) { + public BlockCraftingTable(int meta) { super(meta); } @@ -51,6 +52,7 @@ public int getToolType() { @Override public boolean onActivate(Item item, Player player) { if (player != null) { + player.setCraftingGrid(new BigCraftingGrid(player)); player.craftingType = Player.CRAFTING_BIG; } return true; diff --git a/src/main/java/cn/nukkit/block/BlockEnchantingTable.java b/src/main/java/cn/nukkit/block/BlockEnchantingTable.java index 2619966fe5..d29d132b8a 100644 --- a/src/main/java/cn/nukkit/block/BlockEnchantingTable.java +++ b/src/main/java/cn/nukkit/block/BlockEnchantingTable.java @@ -122,7 +122,7 @@ public boolean onActivate(Item item, Player player) { } } - player.addWindow(new EnchantInventory(this.getLocation())); + player.addWindow(new EnchantInventory(this.getLocation()), Player.ENCHANT_WINDOW_ID); } return true; diff --git a/src/main/java/cn/nukkit/block/BlockEndGateway.java b/src/main/java/cn/nukkit/block/BlockEndGateway.java index 87038f41d7..c87a0ade38 100644 --- a/src/main/java/cn/nukkit/block/BlockEndGateway.java +++ b/src/main/java/cn/nukkit/block/BlockEndGateway.java @@ -4,7 +4,6 @@ import cn.nukkit.utils.BlockColor; /** - * * @author PikyCZ */ public class BlockEndGateway extends BlockSolid { diff --git a/src/main/java/cn/nukkit/block/BlockEndStone.java b/src/main/java/cn/nukkit/block/BlockEndStone.java index d8701c1ed5..ab497aee2e 100644 --- a/src/main/java/cn/nukkit/block/BlockEndStone.java +++ b/src/main/java/cn/nukkit/block/BlockEndStone.java @@ -44,7 +44,7 @@ public int getToolType() { @Override public Item[] getDrops(Item item) { - if (item.isPickaxe() && item.getTier() > ItemTool.TIER_WOODEN) { + if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_WOODEN) { return new Item[]{ toItem() }; diff --git a/src/main/java/cn/nukkit/block/BlockFlowerPot.java b/src/main/java/cn/nukkit/block/BlockFlowerPot.java index 4c8a6c4fbb..1e7648d085 100644 --- a/src/main/java/cn/nukkit/block/BlockFlowerPot.java +++ b/src/main/java/cn/nukkit/block/BlockFlowerPot.java @@ -157,4 +157,9 @@ protected AxisAlignedBB recalculateBoundingBox() { public boolean canPassThrough() { return false; } + + @Override + public Item toItem() { + return new ItemFlowerPot(); + } } diff --git a/src/main/java/cn/nukkit/block/BlockGlassPane.java b/src/main/java/cn/nukkit/block/BlockGlassPane.java index 4da68af165..b2fa9fcd21 100644 --- a/src/main/java/cn/nukkit/block/BlockGlassPane.java +++ b/src/main/java/cn/nukkit/block/BlockGlassPane.java @@ -14,10 +14,9 @@ public BlockGlassPane() { } public BlockGlassPane(int meta) { - super(0); + super(meta); } - @Override public String getName() { return "Glass Pane"; diff --git a/src/main/java/cn/nukkit/block/BlockGlassPaneStained.java b/src/main/java/cn/nukkit/block/BlockGlassPaneStained.java new file mode 100644 index 0000000000..bf3caeba14 --- /dev/null +++ b/src/main/java/cn/nukkit/block/BlockGlassPaneStained.java @@ -0,0 +1,37 @@ +package cn.nukkit.block; + +import cn.nukkit.utils.BlockColor; +import cn.nukkit.utils.DyeColor; + +/** + * Created by CreeperFace on 7.8.2017. + */ +public class BlockGlassPaneStained extends BlockGlassPane { + + public BlockGlassPaneStained() { + this(0); + } + + public BlockGlassPaneStained(int meta) { + super(meta); + } + + @Override + public int getId() { + return STAINED_GLASS_PANE; + } + + @Override + public String getName() { + return getDyeColor().getName() + " stained glass pane"; + } + + @Override + public BlockColor getColor() { + return getDyeColor().getColor(); + } + + public DyeColor getDyeColor() { + return DyeColor.getByWoolData(meta); + } +} diff --git a/src/main/java/cn/nukkit/block/BlockGlassStained.java b/src/main/java/cn/nukkit/block/BlockGlassStained.java new file mode 100644 index 0000000000..a00e545cd1 --- /dev/null +++ b/src/main/java/cn/nukkit/block/BlockGlassStained.java @@ -0,0 +1,37 @@ +package cn.nukkit.block; + +import cn.nukkit.utils.BlockColor; +import cn.nukkit.utils.DyeColor; + +/** + * Created by CreeperFace on 7.8.2017. + */ +public class BlockGlassStained extends BlockGlass { + + public BlockGlassStained() { + this(0); + } + + public BlockGlassStained(int meta) { + super(meta); + } + + @Override + public int getId() { + return STAINED_GLASS; + } + + @Override + public String getName() { + return getDyeColor().getName() + " Stained Glass"; + } + + @Override + public BlockColor getColor() { + return DyeColor.getByWoolData(meta).getColor(); + } + + public DyeColor getDyeColor() { + return DyeColor.getByWoolData(meta); + } +} diff --git a/src/main/java/cn/nukkit/block/BlockGlowstone.java b/src/main/java/cn/nukkit/block/BlockGlowstone.java index b0b623553f..b19c80069a 100644 --- a/src/main/java/cn/nukkit/block/BlockGlowstone.java +++ b/src/main/java/cn/nukkit/block/BlockGlowstone.java @@ -2,8 +2,12 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemGlowstoneDust; +import cn.nukkit.item.enchantment.Enchantment; +import cn.nukkit.math.MathHelper; import cn.nukkit.utils.BlockColor; +import java.util.Random; + /** * Created on 2015/12/6 by xtypr. * Package cn.nukkit.block in project Nukkit . @@ -44,8 +48,16 @@ public int getLightLevel() { @Override public Item[] getDrops(Item item) { + Random random = new Random(); + int count = 2 + random.nextInt(3); + + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + count += random.nextInt(fortune.getLevel() + 1); + } + return new Item[]{ - new ItemGlowstoneDust(0, ((int) (2d * Math.random()) + 2)) + new ItemGlowstoneDust(0, MathHelper.clamp(count, 1, 4)) }; } diff --git a/src/main/java/cn/nukkit/block/BlockJukebox.java b/src/main/java/cn/nukkit/block/BlockJukebox.java new file mode 100644 index 0000000000..419d11d1c7 --- /dev/null +++ b/src/main/java/cn/nukkit/block/BlockJukebox.java @@ -0,0 +1,78 @@ +package cn.nukkit.block; + +import cn.nukkit.Player; +import cn.nukkit.blockentity.BlockEntity; +import cn.nukkit.blockentity.BlockEntityJukebox; +import cn.nukkit.item.Item; +import cn.nukkit.item.ItemRecord; +import cn.nukkit.math.BlockFace; +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.nbt.tag.ListTag; + +/** + * Created by CreeperFace on 7.8.2017. + */ +public class BlockJukebox extends BlockSolid { + + public BlockJukebox() { + this(0); + } + + public BlockJukebox(int meta) { + super(0); + } + + @Override + public String getName() { + return "Jukebox"; + } + + @Override + public int getId() { + return JUKEBOX; + } + + @Override + public boolean canBeActivated() { + return true; + } + + @Override + public boolean onActivate(Item item, Player player) { + BlockEntity blockEntity = this.getLevel().getBlockEntity(this); + if (blockEntity == null || !(blockEntity instanceof BlockEntityJukebox)) { + blockEntity = this.createBlockEntity(); + } + + BlockEntityJukebox jukebox = (BlockEntityJukebox) blockEntity; + if (jukebox.getRecordItem().getId() != 0) { + jukebox.dropItem(); + } else if (item instanceof ItemRecord) { + jukebox.setRecordItem(item); + jukebox.play(); + } + + return false; + } + + @Override + public boolean place(Item item, Block block, Block target, BlockFace face, double fx, double fy, double fz, Player player) { + if (super.place(item, block, target, face, fx, fy, fz, player)) { + createBlockEntity(); + return true; + } + + return false; + } + + private BlockEntity createBlockEntity() { + CompoundTag nbt = new CompoundTag() + .putList(new ListTag<>("Items")) + .putString("id", BlockEntity.JUKEBOX) + .putInt("x", getFloorX()) + .putInt("y", getFloorY()) + .putInt("z", getFloorZ()); + + return BlockEntity.createBlockEntity(BlockEntity.JUKEBOX, this.level.getChunk(getFloorX() >> 4, getFloorZ() >> 4), nbt); + } +} diff --git a/src/main/java/cn/nukkit/block/BlockLever.java b/src/main/java/cn/nukkit/block/BlockLever.java index e1ab5b3ac7..498ed4c695 100644 --- a/src/main/java/cn/nukkit/block/BlockLever.java +++ b/src/main/java/cn/nukkit/block/BlockLever.java @@ -83,7 +83,7 @@ public int onUpdate(int type) { @Override public boolean place(Item item, Block block, Block target, BlockFace face, double fx, double fy, double fz, Player player) { - if (!target.isTransparent() && target.isSolid()) { + if (target.isNormalBlock()) { this.meta = LeverOrientation.forFacings(face, player.getHorizontalFacing()).getMetadata(); this.getLevel().setBlock(block, this, true, true); return true; diff --git a/src/main/java/cn/nukkit/block/BlockMelon.java b/src/main/java/cn/nukkit/block/BlockMelon.java index 0f8e41c513..8b227cdb9f 100644 --- a/src/main/java/cn/nukkit/block/BlockMelon.java +++ b/src/main/java/cn/nukkit/block/BlockMelon.java @@ -3,6 +3,7 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemMelon; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.utils.BlockColor; import java.util.Random; @@ -42,8 +43,16 @@ public double getResistance() { @Override public Item[] getDrops(Item item) { + Random random = new Random(); + int count = 3 + random.nextInt(5); + + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + count += random.nextInt(fortune.getLevel() + 1); + } + return new Item[]{ - new ItemMelon(0, new Random().nextInt(4) + 3) + new ItemMelon(0, Math.min(9, count)) }; } diff --git a/src/main/java/cn/nukkit/block/BlockOreCoal.java b/src/main/java/cn/nukkit/block/BlockOreCoal.java index c03f69ba62..56012c2d25 100644 --- a/src/main/java/cn/nukkit/block/BlockOreCoal.java +++ b/src/main/java/cn/nukkit/block/BlockOreCoal.java @@ -3,8 +3,11 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemCoal; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.math.NukkitRandom; +import java.util.concurrent.ThreadLocalRandom; + /** * author: MagicDroidX * Nukkit Project @@ -47,8 +50,20 @@ public String getName() { @Override public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_WOODEN) { + int count = 1; + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + int i = ThreadLocalRandom.current().nextInt(fortune.getLevel() + 2) - 1; + + if (i < 0) { + i = 0; + } + + count = i + 1; + } + return new Item[]{ - new ItemCoal() + new ItemCoal(0, count) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockOreDiamond.java b/src/main/java/cn/nukkit/block/BlockOreDiamond.java index ec06031fef..31dcaf22b4 100644 --- a/src/main/java/cn/nukkit/block/BlockOreDiamond.java +++ b/src/main/java/cn/nukkit/block/BlockOreDiamond.java @@ -3,8 +3,11 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemDiamond; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.math.NukkitRandom; +import java.util.concurrent.ThreadLocalRandom; + /** * author: MagicDroidX * Nukkit Project @@ -48,8 +51,20 @@ public String getName() { @Override public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_IRON) { + int count = 1; + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + int i = ThreadLocalRandom.current().nextInt(fortune.getLevel() + 2) - 1; + + if (i < 0) { + i = 0; + } + + count = i + 1; + } + return new Item[]{ - new ItemDiamond() + new ItemDiamond(0, count) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockOreEmerald.java b/src/main/java/cn/nukkit/block/BlockOreEmerald.java index c0afbd0d9e..1e81d7d144 100644 --- a/src/main/java/cn/nukkit/block/BlockOreEmerald.java +++ b/src/main/java/cn/nukkit/block/BlockOreEmerald.java @@ -3,8 +3,11 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemEmerald; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.math.NukkitRandom; +import java.util.concurrent.ThreadLocalRandom; + /** * Created on 2015/12/1 by xtypr. * Package cn.nukkit.block in project Nukkit . @@ -47,8 +50,20 @@ public double getResistance() { @Override public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_IRON) { + int count = 1; + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + int i = ThreadLocalRandom.current().nextInt(fortune.getLevel() + 2) - 1; + + if (i < 0) { + i = 0; + } + + count = i + 1; + } + return new Item[]{ - new ItemEmerald() + new ItemEmerald(0, count) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockOreGold.java b/src/main/java/cn/nukkit/block/BlockOreGold.java index e46c15d5ea..c3d1d47a8a 100644 --- a/src/main/java/cn/nukkit/block/BlockOreGold.java +++ b/src/main/java/cn/nukkit/block/BlockOreGold.java @@ -46,7 +46,7 @@ public String getName() { public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_IRON) { return new Item[]{ - toItem() + Item.get(GOLD_ORE) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockOreIron.java b/src/main/java/cn/nukkit/block/BlockOreIron.java index 057c632e51..87e62af814 100644 --- a/src/main/java/cn/nukkit/block/BlockOreIron.java +++ b/src/main/java/cn/nukkit/block/BlockOreIron.java @@ -47,7 +47,7 @@ public String getName() { public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_STONE) { return new Item[]{ - toItem() + Item.get(IRON_ORE) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockOreLapis.java b/src/main/java/cn/nukkit/block/BlockOreLapis.java index 6fc943a0de..23b6957d47 100644 --- a/src/main/java/cn/nukkit/block/BlockOreLapis.java +++ b/src/main/java/cn/nukkit/block/BlockOreLapis.java @@ -3,9 +3,11 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemDye; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.math.NukkitRandom; import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; /** * author: MagicDroidX @@ -50,6 +52,18 @@ public String getName() { @Override public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_STONE) { + int count = 4 + ThreadLocalRandom.current().nextInt(5); + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + int i = ThreadLocalRandom.current().nextInt(fortune.getLevel() + 2) - 1; + + if (i < 0) { + i = 0; + } + + count *= (i + 1); + } + return new Item[]{ new ItemDye(4, new Random().nextInt(4) + 4) }; diff --git a/src/main/java/cn/nukkit/block/BlockOreQuartz.java b/src/main/java/cn/nukkit/block/BlockOreQuartz.java index 2fede06996..135eab5fa1 100644 --- a/src/main/java/cn/nukkit/block/BlockOreQuartz.java +++ b/src/main/java/cn/nukkit/block/BlockOreQuartz.java @@ -3,8 +3,11 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemQuartz; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.math.NukkitRandom; +import java.util.concurrent.ThreadLocalRandom; + /** * Created on 2015/12/26 by xtypr. * Package cn.nukkit.block in project Nukkit . @@ -47,8 +50,20 @@ public int getToolType() { @Override public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_WOODEN) { + int count = 1; + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + int i = ThreadLocalRandom.current().nextInt(fortune.getLevel() + 2) - 1; + + if (i < 0) { + i = 0; + } + + count = i + 1; + } + return new Item[]{ - new ItemQuartz() + new ItemQuartz(0, count) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockOreRedstone.java b/src/main/java/cn/nukkit/block/BlockOreRedstone.java index 0c3cd1cbe7..0357dfd6dd 100644 --- a/src/main/java/cn/nukkit/block/BlockOreRedstone.java +++ b/src/main/java/cn/nukkit/block/BlockOreRedstone.java @@ -3,6 +3,7 @@ import cn.nukkit.item.Item; import cn.nukkit.item.ItemRedstone; import cn.nukkit.item.ItemTool; +import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.level.Level; import cn.nukkit.math.NukkitRandom; @@ -50,8 +51,15 @@ public String getName() { @Override public Item[] getDrops(Item item) { if (item.isPickaxe() && item.getTier() >= ItemTool.TIER_IRON) { + int count = new Random().nextInt(2) + 4; + + Enchantment fortune = item.getEnchantment(Enchantment.ID_FORTUNE_DIGGING); + if (fortune != null && fortune.getLevel() >= 1) { + count += new Random().nextInt(fortune.getLevel() + 1); + } + return new Item[]{ - new ItemRedstone(0, new Random().nextInt(1) + 4) + new ItemRedstone(0, count) }; } else { return new Item[0]; diff --git a/src/main/java/cn/nukkit/block/BlockPistonBase.java b/src/main/java/cn/nukkit/block/BlockPistonBase.java index 06de9688b5..b1c0d16383 100644 --- a/src/main/java/cn/nukkit/block/BlockPistonBase.java +++ b/src/main/java/cn/nukkit/block/BlockPistonBase.java @@ -1,12 +1,16 @@ package cn.nukkit.block; import cn.nukkit.Player; +import cn.nukkit.blockentity.BlockEntity; +import cn.nukkit.blockentity.BlockEntityPistonArm; +import cn.nukkit.event.block.BlockPistonChangeEvent; import cn.nukkit.item.Item; import cn.nukkit.level.Level; import cn.nukkit.level.sound.PistonInSound; import cn.nukkit.level.sound.PistonOutSound; import cn.nukkit.math.BlockFace; import cn.nukkit.math.Vector3; +import cn.nukkit.nbt.tag.CompoundTag; import java.util.ArrayList; import java.util.List; @@ -53,14 +57,14 @@ public boolean place(Item item, Block block, Block target, BlockFace face, doubl } this.level.setBlock(block, this, true, false); - /*CompoundTag nbt = new CompoundTag("") + CompoundTag nbt = new CompoundTag("") .putString("id", BlockEntity.PISTON_ARM) .putInt("x", (int) this.x) .putInt("y", (int) this.y) .putInt("z", (int) this.z) - .putBoolean("Sticky", this.sticky);*/ + .putBoolean("Sticky", this.sticky); - //BlockEntityPistonArm be = new BlockEntityPistonArm(this.level.getChunk((int) this.x >> 4, (int) this.z >> 4), nbt); bug? + BlockEntityPistonArm be = new BlockEntityPistonArm(this.level.getChunk((int) this.x >> 4, (int) this.z >> 4), nbt); //this.checkState(); return true; @@ -86,12 +90,24 @@ public boolean isExtended() { @Override public int onUpdate(int type) { - if (type == Level.BLOCK_UPDATE_REDSTONE || type == Level.BLOCK_UPDATE_NORMAL) { - //checkState(); + if (type != 6 && type != 1) { + return 0; + } else { + BlockEntity blockEntity = this.level.getBlockEntity(this); + if (blockEntity instanceof BlockEntityPistonArm) { + BlockEntityPistonArm arm = (BlockEntityPistonArm) blockEntity; + boolean powered = this.isPowered(); + if (arm.powered != powered) { + this.level.getServer().getPluginManager().callEvent(new BlockPistonChangeEvent(this, powered ? 0 : 15, powered ? 15 : 0)); + arm.powered = !arm.powered; + if (arm.chunk != null) { + arm.chunk.setChanged(); + } + } + } + return type; } - - return 0; } private void checkState() { diff --git a/src/main/java/cn/nukkit/block/BlockPlanks.java b/src/main/java/cn/nukkit/block/BlockPlanks.java index 7d5d79c8a0..be8eda1a9e 100644 --- a/src/main/java/cn/nukkit/block/BlockPlanks.java +++ b/src/main/java/cn/nukkit/block/BlockPlanks.java @@ -21,7 +21,7 @@ public BlockPlanks() { } public BlockPlanks(int meta) { - super(meta); + super(meta % 6); } @Override diff --git a/src/main/java/cn/nukkit/block/BlockPressurePlateBase.java b/src/main/java/cn/nukkit/block/BlockPressurePlateBase.java index 6c6a2c9443..c19e296fbe 100644 --- a/src/main/java/cn/nukkit/block/BlockPressurePlateBase.java +++ b/src/main/java/cn/nukkit/block/BlockPressurePlateBase.java @@ -1,7 +1,12 @@ package cn.nukkit.block; +import cn.nukkit.Player; import cn.nukkit.entity.Entity; +import cn.nukkit.event.Event; import cn.nukkit.event.block.BlockRedstoneEvent; +import cn.nukkit.event.entity.EntityInteractEvent; +import cn.nukkit.event.player.PlayerInteractEvent; +import cn.nukkit.event.player.PlayerInteractEvent.Action; import cn.nukkit.item.Item; import cn.nukkit.item.ItemBlock; import cn.nukkit.level.Level; @@ -92,7 +97,19 @@ public void onEntityCollide(Entity entity) { int power = getRedstonePower(); if (power == 0) { - updateState(power); + Event ev; + + if (entity instanceof Player) { + ev = new PlayerInteractEvent((Player) entity, null, this, null, Action.PHYSICAL); + } else { + ev = new EntityInteractEvent(entity, this); + } + + this.level.getServer().getPluginManager().callEvent(ev); + + if (!ev.isCancelled()) { + updateState(power); + } } } diff --git a/src/main/java/cn/nukkit/block/BlockRail.java b/src/main/java/cn/nukkit/block/BlockRail.java index debed246f1..54119ae2e6 100644 --- a/src/main/java/cn/nukkit/block/BlockRail.java +++ b/src/main/java/cn/nukkit/block/BlockRail.java @@ -1,7 +1,6 @@ package cn.nukkit.block; import cn.nukkit.Player; -import cn.nukkit.Server; import cn.nukkit.item.Item; import cn.nukkit.item.ItemTool; import cn.nukkit.level.Level; diff --git a/src/main/java/cn/nukkit/block/BlockRailActivator.java b/src/main/java/cn/nukkit/block/BlockRailActivator.java index c7c33339a9..e0e91bf35f 100644 --- a/src/main/java/cn/nukkit/block/BlockRailActivator.java +++ b/src/main/java/cn/nukkit/block/BlockRailActivator.java @@ -57,9 +57,9 @@ public int onUpdate(int type) { /** * Check the surrounding of the rail * - * @param pos The rail position + * @param pos The rail position * @param relative The relative of the rail that will be checked - * @param power The count of the rail that had been counted + * @param power The count of the rail that had been counted * @return Boolean of the surrounding area. Where the powered rail on! */ protected boolean checkSurrounding(Vector3 pos, boolean relative, int power) { @@ -69,7 +69,7 @@ protected boolean checkSurrounding(Vector3 pos, boolean relative, int power) { int dx = pos.getFloorX(); int dy = pos.getFloorY(); int dz = pos.getFloorZ(); - + BlockRail block; Block block2 = level.getBlock(new Vector3(dx, dy, dz)); @@ -153,7 +153,7 @@ protected boolean canPowered(Vector3 pos, Rail.Orientation state, int power, boo } Rail.Orientation base = ((BlockRailActivator) block).getOrientation(); - + return (state != Rail.Orientation.STRAIGHT_EAST_WEST || base != Rail.Orientation.STRAIGHT_NORTH_SOUTH && base != Rail.Orientation.ASCENDING_NORTH diff --git a/src/main/java/cn/nukkit/block/BlockRailDetector.java b/src/main/java/cn/nukkit/block/BlockRailDetector.java index 563821914c..83818621d2 100644 --- a/src/main/java/cn/nukkit/block/BlockRailDetector.java +++ b/src/main/java/cn/nukkit/block/BlockRailDetector.java @@ -52,7 +52,7 @@ public int getStrongPower(BlockFace side) { @Override public int onUpdate(int type) { - if (type == Level.BLOCK_UPDATE_SCHEDULED) { + if (type == Level.BLOCK_UPDATE_SCHEDULED) { updateState(); return type; } diff --git a/src/main/java/cn/nukkit/block/BlockRailPowered.java b/src/main/java/cn/nukkit/block/BlockRailPowered.java index bdd3966779..3350d60728 100644 --- a/src/main/java/cn/nukkit/block/BlockRailPowered.java +++ b/src/main/java/cn/nukkit/block/BlockRailPowered.java @@ -5,7 +5,7 @@ import cn.nukkit.utils.Rail; /** - * Created by Snake1999 on 2016/1/11. + * Created by Snake1999 on 2016/1/11. * Contributed by: larryTheCoder on 2017/7/18. *

* Nukkit Project, @@ -62,9 +62,9 @@ public int onUpdate(int type) { /** * Check the surrounding of the rail * - * @param pos The rail position + * @param pos The rail position * @param relative The relative of the rail that will be checked - * @param power The count of the rail that had been counted + * @param power The count of the rail that had been counted * @return Boolean of the surrounding area. Where the powered rail on! */ protected boolean checkSurrounding(Vector3 pos, boolean relative, int power) { @@ -86,7 +86,7 @@ protected boolean checkSurrounding(Vector3 pos, boolean relative, int power) { } else { return false; } - + // Used to check if the next ascending rail should be what Rail.Orientation base = null; boolean onStraight = true; @@ -150,7 +150,7 @@ protected boolean checkSurrounding(Vector3 pos, boolean relative, int power) { // Unable to determinate the rail orientation // Wrong rail? return false; - } + } // Next check the if rail is on power state return canPowered(new Vector3(dx, dy, dz), base, power, relative) || onStraight && canPowered(new Vector3(dx, dy - 1, dz), base, power, relative); @@ -168,14 +168,14 @@ protected boolean canPowered(Vector3 pos, Rail.Orientation state, int power, boo // Possible way how to know when the rail is activated is rail were directly powered // OR recheck the surrounding... Which will returns here =w= - return (state != Rail.Orientation.STRAIGHT_EAST_WEST - || base != Rail.Orientation.STRAIGHT_NORTH_SOUTH - && base != Rail.Orientation.ASCENDING_NORTH - && base != Rail.Orientation.ASCENDING_SOUTH) - && (state != Rail.Orientation.STRAIGHT_NORTH_SOUTH - || base != Rail.Orientation.STRAIGHT_EAST_WEST - && base != Rail.Orientation.ASCENDING_EAST - && base != Rail.Orientation.ASCENDING_WEST) + return (state != Rail.Orientation.STRAIGHT_EAST_WEST + || base != Rail.Orientation.STRAIGHT_NORTH_SOUTH + && base != Rail.Orientation.ASCENDING_NORTH + && base != Rail.Orientation.ASCENDING_SOUTH) + && (state != Rail.Orientation.STRAIGHT_NORTH_SOUTH + || base != Rail.Orientation.STRAIGHT_EAST_WEST + && base != Rail.Orientation.ASCENDING_EAST + && base != Rail.Orientation.ASCENDING_WEST) && (level.isBlockPowered(pos) || checkSurrounding(pos, relative, power + 1)); } diff --git a/src/main/java/cn/nukkit/block/BlockTripWireHook.java b/src/main/java/cn/nukkit/block/BlockTripWireHook.java index aed58677d2..1ed0edc6bc 100644 --- a/src/main/java/cn/nukkit/block/BlockTripWireHook.java +++ b/src/main/java/cn/nukkit/block/BlockTripWireHook.java @@ -177,15 +177,15 @@ public void calculateState(boolean onBreak, boolean updateAround, int pos, Block private void addSound(Vector3 pos, boolean canConnect, boolean nextPowered, boolean attached, boolean powered) { if (nextPowered && !powered) { - this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_POWER_ON, 1, -1, pos, false, false); + this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_POWER_ON, 1, -1, pos); this.level.getServer().getPluginManager().callEvent(new BlockRedstoneEvent(this, 0, 15)); } else if (!nextPowered && powered) { - this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_POWER_OFF, 1, -1, pos, false, false); + this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_POWER_OFF, 1, -1, pos); this.level.getServer().getPluginManager().callEvent(new BlockRedstoneEvent(this, 15, 0)); } else if (canConnect && !attached) { - this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_ATTACH, 1, -1, pos, false, false); + this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_ATTACH, 1, -1, pos); } else if (!canConnect && attached) { - this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_DETACH, 1, -1, pos, false, false); + this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_DETACH, 1, -1, pos); } } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntity.java b/src/main/java/cn/nukkit/blockentity/BlockEntity.java index 58c72dbf91..f0571ec255 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntity.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntity.java @@ -38,6 +38,7 @@ public abstract class BlockEntity extends Position { public static final String COMPARATOR = "Comparator"; public static final String HOPPER = "Hopper"; public static final String BED = "Bed"; + public static final String JUKEBOX = "Jukebox"; public static long count = 1; @@ -49,6 +50,8 @@ public abstract class BlockEntity extends Position { public String name; public long id; + public boolean movable = true; + public boolean closed = false; public CompoundTag namedTag; protected long lastUpdate; @@ -71,6 +74,7 @@ public BlockEntity(FullChunk chunk, CompoundTag nbt) { this.x = this.namedTag.getInt("x"); this.y = this.namedTag.getInt("y"); this.z = this.namedTag.getInt("z"); + this.movable = this.namedTag.getBoolean("isMovable"); this.chunk.addBlockEntity(this); this.getLevel().addBlockEntity(this); @@ -141,21 +145,22 @@ public void saveNBT() { this.namedTag.putInt("x", (int) this.getX()); this.namedTag.putInt("y", (int) this.getY()); this.namedTag.putInt("z", (int) this.getZ()); + this.namedTag.putBoolean("isMovable", this.movable); } - public CompoundTag getCleanedNBT(){ + public CompoundTag getCleanedNBT() { this.saveNBT(); CompoundTag tag = this.namedTag.clone(); tag.remove("x").remove("y").remove("z").remove("id"); - if(tag.getTags().size() > 0){ + if (tag.getTags().size() > 0) { return tag; - }else{ + } else { return null; } } public Block getBlock() { - return this.level.getBlock(this); + return this.getLevelBlock(); } public abstract boolean isBlockEntityValid(); @@ -186,6 +191,10 @@ public String getName() { return name; } + public boolean isMovable() { + return movable; + } + public static CompoundTag getDefaultCompound(Vector3 pos, String id) { return new CompoundTag("") .putString("id", id) diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java b/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java index ecf277b113..ec033ad95e 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityBrewingStand.java @@ -1,10 +1,12 @@ package cn.nukkit.blockentity; - import cn.nukkit.Player; import cn.nukkit.Server; import cn.nukkit.block.Block; import cn.nukkit.block.BlockAir; +import cn.nukkit.block.BlockBrewingStand; +import cn.nukkit.event.inventory.BrewEvent; +import cn.nukkit.event.inventory.StartBrewEvent; import cn.nukkit.inventory.BrewingInventory; import cn.nukkit.inventory.BrewingRecipe; import cn.nukkit.inventory.InventoryHolder; @@ -28,6 +30,8 @@ public class BlockEntityBrewingStand extends BlockEntitySpawnable implements Inv public static final int MAX_BREW_TIME = 400; public int brewTime = MAX_BREW_TIME; + public int fuelTotal; + public int fuelAmount; public static final List ingredients = new ArrayList() { { @@ -53,6 +57,9 @@ public BlockEntityBrewingStand(FullChunk chunk, CompoundTag nbt) { this.brewTime = namedTag.getShort("CookTime"); } + this.fuelAmount = namedTag.getShort("FuelAmount"); + this.fuelTotal = namedTag.getShort("FuelTotal"); + if (brewTime < MAX_BREW_TIME) { this.scheduleUpdate(); } @@ -96,6 +103,8 @@ public void saveNBT() { } namedTag.putShort("CookTime", brewTime); + namedTag.putShort("FuelAmount", this.fuelAmount); + namedTag.putShort("FuelTotal", this.fuelTotal); } @Override @@ -167,46 +176,65 @@ public boolean onUpdate() { Item ingredient = this.inventory.getIngredient(); boolean canBrew = false; - for (int i = 1; i <= 3; i++) { - if (this.inventory.getItem(i).getId() == Item.POTION) { - canBrew = true; - } + Item fuel = this.getInventory().getFuel(); + if (this.fuelAmount <= 0 && fuel.getId() == Item.BLAZE_POWDER && fuel.getCount() > 0) { + fuel.count--; + this.fuelAmount = 20; + this.fuelTotal = 20; + + this.inventory.setFuel(fuel); + this.sendFuel(); } - if (this.brewTime <= MAX_BREW_TIME && canBrew && ingredient.getCount() > 0) { - if (!this.checkIngredient(ingredient)) { + if (this.fuelAmount > 0) { + for (int i = 1; i <= 3; i++) { + if (this.inventory.getItem(i).getId() == Item.POTION) { + canBrew = true; + } + } + + if (this.brewTime <= MAX_BREW_TIME && canBrew && ingredient.getCount() > 0) { + if (!this.checkIngredient(ingredient)) { + canBrew = false; + } + } else { canBrew = false; } - } else { - canBrew = false; } if (canBrew) { - this.brewTime--; + if (this.brewTime == MAX_BREW_TIME) { + this.sendBrewTime(); + StartBrewEvent e = new StartBrewEvent(this); + this.server.getPluginManager().callEvent(e); - for (Player player : this.inventory.getViewers()) { - int windowId = player.getWindowId(this.inventory); - if (windowId > 0) { - ContainerSetDataPacket pk = new ContainerSetDataPacket(); - pk.windowid = (byte) windowId; - pk.property = 0; - pk.value = this.brewTime; - player.dataPacket(pk); + if (e.isCancelled()) { + return false; } } + this.brewTime--; + if (this.brewTime <= 0) { //20 seconds - for (int i = 1; i <= 3; i++) { - Item potion = this.inventory.getItem(i); - BrewingRecipe recipe = Server.getInstance().getCraftingManager().matchBrewingRecipe(ingredient, potion); + BrewEvent e = new BrewEvent(this); + this.server.getPluginManager().callEvent(e); - if (recipe != null) { - this.inventory.setItem(i, recipe.getResult()); + if (!e.isCancelled()) { + for (int i = 1; i <= 3; i++) { + Item potion = this.inventory.getItem(i); + BrewingRecipe recipe = Server.getInstance().getCraftingManager().matchBrewingRecipe(ingredient, potion); + + if (recipe != null) { + this.inventory.setItem(i, recipe.getResult()); + } } - } - ingredient.count--; - this.inventory.setIngredient(ingredient); + ingredient.count--; + this.inventory.setIngredient(ingredient); + + this.fuelAmount--; + this.sendFuel(); + } this.brewTime = MAX_BREW_TIME; } @@ -216,11 +244,75 @@ public boolean onUpdate() { this.brewTime = MAX_BREW_TIME; } + //this.sendBrewTime(); lastUpdate = System.currentTimeMillis(); return ret; } + protected void sendFuel() { + ContainerSetDataPacket pk = new ContainerSetDataPacket(); + + for (Player p : this.inventory.getViewers()) { + int windowId = p.getWindowId(this.inventory); + if (windowId > 0) { + pk.windowId = windowId; + + pk.property = ContainerSetDataPacket.PROPERTY_BREWING_STAND_FUEL_AMOUNT; + pk.value = this.fuelAmount; + p.dataPacket(pk); + + pk.property = ContainerSetDataPacket.PROPERTY_BREWING_STAND_FUEL_TOTAL; + pk.value = this.fuelTotal; + p.dataPacket(pk); + } + } + } + + protected void sendBrewTime() { + ContainerSetDataPacket pk = new ContainerSetDataPacket(); + pk.property = ContainerSetDataPacket.PROPERTY_BREWING_STAND_BREW_TIME; + pk.value = this.brewTime; + + for (Player p : this.inventory.getViewers()) { + int windowId = p.getWindowId(this.inventory); + if (windowId > 0) { + pk.windowId = windowId; + + p.dataPacket(pk); + } + } + } + + public void updateBlock() { + Block block = this.getLevelBlock(); + + if (!(block instanceof BlockBrewingStand)) { + return; + } + + int meta = 0; + + for (int i = 1; i <= 3; ++i) { + Item potion = this.inventory.getItem(i); + + if (potion.getId() == Item.POTION && potion.getCount() > 0) { + meta |= 1 << i; + } + } + + block.setDamage(meta); + this.level.setBlock(block, block, false, false); + } + + public int getFuel() { + return fuelAmount; + } + + public void setFuel(int fuel) { + this.fuelAmount = fuel; + } + @Override public CompoundTag getSpawnCompound() { CompoundTag nbt = new CompoundTag() @@ -228,7 +320,12 @@ public CompoundTag getSpawnCompound() { .putInt("x", (int) this.x) .putInt("y", (int) this.y) .putInt("z", (int) this.z) - .putShort("CookTime", 0); + .putShort("FuelTotal", this.fuelTotal) + .putShort("FuelAmount", this.fuelAmount); + + if (this.brewTime < MAX_BREW_TIME) { + nbt.putShort("CookTime", this.brewTime); + } if (this.hasName()) { nbt.put("CustomName", namedTag.get("CustomName")); diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityChest.java b/src/main/java/cn/nukkit/blockentity/BlockEntityChest.java index c4f2df249a..f4cdeab250 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityChest.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityChest.java @@ -38,7 +38,7 @@ public BlockEntityChest(FullChunk chunk, CompoundTag nbt) { /* for (int i = 0; i < this.getSize(); i++) { this.inventory.setItem(i, this.getItem(i)); } */ - + ListTag list = (ListTag) this.namedTag.getList("Items"); for (CompoundTag compound : list.getAll()) { Item item = NBTIO.getItemHelper(compound); @@ -104,7 +104,7 @@ public Item getItem(int index) { @Override public void setItem(int index, Item item) { int i = this.getSlotIndex(index); - + CompoundTag d = NBTIO.putItemHelper(item, index); // If item is air or count less than 0, remove the item from the "Items" list @@ -116,14 +116,14 @@ public void setItem(int index, Item item) { // If it is less than i, then it is a new item, so we are going to add it at the end of the list (this.namedTag.getList("Items", CompoundTag.class)).add(d); } else { - // If it is more than i, then it is an update on a slot, so we are going to overwrite the item in the list + // If it is more than i, then it is an update on a inventorySlot, so we are going to overwrite the item in the list (this.namedTag.getList("Items", CompoundTag.class)).add(i, d); } } @Override public BaseInventory getInventory() { - if (this.isPaired() && this.doubleInventory == null) { + if (this.doubleInventory == null && this.isPaired()) { this.checkPairing(); } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java b/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java index 4cac086701..6e3265c627 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityFurnace.java @@ -262,14 +262,15 @@ public boolean onUpdate() { int windowId = player.getWindowId(this.getInventory()); if (windowId > 0) { ContainerSetDataPacket pk = new ContainerSetDataPacket(); - pk.windowid = (byte) windowId; - pk.property = 0; + pk.windowId = windowId; + pk.property = ContainerSetDataPacket.PROPERTY_FURNACE_TICK_COUNT; + ; pk.value = cookTime; player.dataPacket(pk); pk = new ContainerSetDataPacket(); - pk.windowid = (byte) windowId; - pk.property = 1; + pk.windowId = windowId; + pk.property = ContainerSetDataPacket.PROPERTY_FURNACE_LIT_TIME; pk.value = burnDuration; player.dataPacket(pk); } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityHopper.java b/src/main/java/cn/nukkit/blockentity/BlockEntityHopper.java index 9bdc5fd129..000a378045 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityHopper.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityHopper.java @@ -146,7 +146,7 @@ public boolean onUpdate() { if (this.closed) { return false; } - + this.transferCooldown--; if (!this.isOnTransferCooldown()) { diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityItemFrame.java b/src/main/java/cn/nukkit/blockentity/BlockEntityItemFrame.java index ef5aad0f82..222a1b0490 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityItemFrame.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityItemFrame.java @@ -96,8 +96,8 @@ public CompoundTag getSpawnCompound() { .putInt("z", (int) this.z) .putCompound("Item", item ? NBTIO.putItemHelper(new ItemBlock(new BlockAir())) : NBTItem) .putByte("ItemRotation", item ? 0 : this.getItemRotation()); - // TODO: This crashes the client, why? - // .putFloat("ItemDropChance", this.getItemDropChance()); + // TODO: This crashes the client, why? + // .putFloat("ItemDropChance", this.getItemDropChance()); } public int getAnalogOutput() { diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityJukebox.java b/src/main/java/cn/nukkit/blockentity/BlockEntityJukebox.java new file mode 100644 index 0000000000..6ae882863d --- /dev/null +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityJukebox.java @@ -0,0 +1,70 @@ +package cn.nukkit.blockentity; + +import cn.nukkit.Server; +import cn.nukkit.block.Block; +import cn.nukkit.item.Item; +import cn.nukkit.item.ItemRecord; +import cn.nukkit.level.format.FullChunk; +import cn.nukkit.nbt.NBTIO; +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +import java.util.Objects; + +/** + * @author CreeperFace + */ +public class BlockEntityJukebox extends BlockEntitySpawnable { + + private Item recordItem; + + public BlockEntityJukebox(FullChunk chunk, CompoundTag nbt) { + super(chunk, nbt); + + this.recordItem = NBTIO.getItemHelper(nbt.getCompound("RecordItem")); + } + + @Override + public boolean isBlockEntityValid() { + return this.getLevel().getBlockIdAt(getFloorX(), getFloorY(), getFloorZ()) == Block.JUKEBOX; + } + + public void setRecordItem(Item recordItem) { + Objects.requireNonNull(recordItem, "Record item cannot be null"); + this.recordItem = recordItem; + } + + public Item getRecordItem() { + return recordItem; + } + + public void play() { + if (this.recordItem instanceof ItemRecord) { + LevelSoundEventPacket pk = new LevelSoundEventPacket(); + pk.sound = ((ItemRecord) this.recordItem).getSoundId(); + pk.pitch = 1; + pk.extraData = -1; + pk.x = (float) this.x; + pk.y = (float) this.y; + pk.z = (float) this.z; + + Server.broadcastPacket(this.level.getPlayers().values(), pk); + } + } + + public void dropItem() { + this.level.dropItem(this.up(), this.recordItem); + } + + @Override + public void saveNBT() { + super.saveNBT(); + this.namedTag.putCompound("RecordItem", NBTIO.putItemHelper(this.recordItem)); + } + + @Override + public CompoundTag getSpawnCompound() { + return getDefaultCompound(this, JUKEBOX) + .putCompound("RecordItem", NBTIO.putItemHelper(this.recordItem)); + } +} diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java b/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java index f97de378da..23793af123 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntityPistonArm.java @@ -1,6 +1,5 @@ package cn.nukkit.blockentity; -import cn.nukkit.Player; import cn.nukkit.entity.Entity; import cn.nukkit.level.format.FullChunk; import cn.nukkit.math.AxisAlignedBB; @@ -13,30 +12,27 @@ /** * @author CreeperFace */ -public class BlockEntityPistonArm extends BlockEntitySpawnable { +public class BlockEntityPistonArm extends BlockEntity { - public float progress = 1f; - public float lastProgress = 1f; + public float progress = 1.0F; + public float lastProgress = 1.0F; public BlockFace facing; public boolean extending = false; public boolean sticky = false; - public byte state = 1; public byte newState = 1; - public Vector3 attachedBlock = null; - public boolean isMovable = true; + public boolean powered = false; public BlockEntityPistonArm(FullChunk chunk, CompoundTag nbt) { super(chunk, nbt); - if (nbt.contains("Progress")) { this.progress = nbt.getFloat("Progress"); } if (nbt.contains("LastProgress")) { - this.lastProgress = nbt.getInt("LastProgress"); + this.lastProgress = (float) nbt.getInt("LastProgress"); } if (nbt.contains("Sticky")) { @@ -47,68 +43,42 @@ public BlockEntityPistonArm(FullChunk chunk, CompoundTag nbt) { this.extending = nbt.getBoolean("Extending"); } + if (nbt.contains("powered")) { + this.powered = nbt.getBoolean("powered"); + } + if (nbt.contains("AttachedBlocks")) { - ListTag blocks = nbt.getList("AttachedBlocks", IntTag.class); + ListTag blocks = nbt.getList("AttachedBlocks", IntTag.class); if (blocks != null && blocks.size() > 0) { - this.attachedBlock = new Vector3(blocks.get(0).getData(), blocks.get(1).getData(), blocks.get(2).getData()); + this.attachedBlock = new Vector3((double) ((IntTag) blocks.get(0)).getData().intValue(), (double) ((IntTag) blocks.get(1)).getData().intValue(), (double) ((IntTag) blocks.get(2)).getData().intValue()); } } else { - nbt.putList(new ListTag("AttachedBlocks")); + nbt.putList(new ListTag("AttachedBlocks")); } - } - - /*@Override - public boolean onUpdate() { - this.lastProgress = this.progress; - - if (this.lastProgress >= 1) { - if(this.newState == 2) { - this.spawnToAll(); - this.state = 2; - return true; - } - - this.newState = 2; - this.spawnToAll(); - this.pushEntities(); - } else { - this.progress += 0.5; - - if (this.progress >= 1) { - this.progress = 1; - } - - this.pushEntities(); - this.spawnToAll(); - } - - return this.state != 2; - }*/ + } private void pushEntities() { float lastProgress = this.getExtendedProgress(this.lastProgress); - double x = lastProgress * (float) this.facing.getXOffset(); - double y = lastProgress * (float) this.facing.getYOffset(); - double z = lastProgress * (float) this.facing.getZOffset(); - AxisAlignedBB bb = new AxisAlignedBB(x, y, z, x + 1, y + 1, z + 1); + double x = (double) (lastProgress * (float) this.facing.getXOffset()); + double y = (double) (lastProgress * (float) this.facing.getYOffset()); + double z = (double) (lastProgress * (float) this.facing.getZOffset()); + AxisAlignedBB bb = new AxisAlignedBB(x, y, z, x + 1.0D, y + 1.0D, z + 1.0D); Entity[] entities = this.level.getCollidingEntities(bb); - if (entities.length != 0) { - //TODO: + ; } + } private float getExtendedProgress(float progress) { return this.extending ? progress - 1.0F : 1.0F - progress; } - @Override public boolean isBlockEntityValid() { return true; } - @Override public void saveNBT() { super.saveNBT(); this.namedTag.putBoolean("isMovable", this.isMovable); @@ -116,35 +86,10 @@ public void saveNBT() { this.namedTag.putByte("NewState", this.newState); this.namedTag.putFloat("Progress", this.progress); this.namedTag.putFloat("LastProgress", this.lastProgress); + this.namedTag.putBoolean("powered", this.powered); } - @Override - public void spawnTo(Player player) { - super.spawnTo(player); - - //System.out.println("spawn X: "+this.x+" Y: "+this.y+" Z: "+this.z); - } - - @Override public CompoundTag getSpawnCompound() { - /*return new CompoundTag() - .putString("id", BlockEntity.PISTON_ARM) - .putInt("x", (int) this.x) - .putInt("y", (int) this.y) - .putInt("z", (int) this.z) - .putFloat("Progress", this.progress) - .putFloat("LastProgress", this.lastProgress) - .putBoolean("isMovable", this.isMovable) - .putList(new ListTag<>("AttachedBlocks")) - .putList(new ListTag<>("BreakBlocks")) - .putBoolean("Sticky", this.sticky) - .putByte("State", this.state) - .putByte("NewState", this.newState);*/ - - return new CompoundTag() - .putString("id", BlockEntity.PISTON_ARM) - .putInt("x", (int) this.x) - .putInt("y", (int) this.y) - .putInt("z", (int) this.z); + return (new CompoundTag()).putString("id", "PistonArm").putInt("x", (int) this.x).putInt("y", (int) this.y).putInt("z", (int) this.z); } } \ No newline at end of file diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntitySign.java b/src/main/java/cn/nukkit/blockentity/BlockEntitySign.java index 23f73a1991..2a3e212fd5 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntitySign.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntitySign.java @@ -1,8 +1,15 @@ package cn.nukkit.blockentity; +import cn.nukkit.Player; import cn.nukkit.block.Block; +import cn.nukkit.event.block.SignChangeEvent; import cn.nukkit.level.format.FullChunk; import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.utils.TextFormat; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; /** * author: MagicDroidX @@ -12,19 +19,24 @@ public class BlockEntitySign extends BlockEntitySpawnable { public BlockEntitySign(FullChunk chunk, CompoundTag nbt) { super(chunk, nbt); - if (!nbt.contains("Text1")) { - nbt.putString("Text1", ""); - } - if (!nbt.contains("Text2")) { - nbt.putString("Text2", ""); - } - if (!nbt.contains("Text3")) { - nbt.putString("Text3", ""); - } - if (!nbt.contains("Text4")) { - nbt.putString("Text4", ""); + + if (!nbt.contains("Text")) { + List lines = new ArrayList<>(); + + for (int i = 1; i <= 4; i++) { + String key = "Text" + i; + + if (nbt.contains(key)) { + String line = nbt.getString(key); + + lines.add(line); + + nbt.remove(key); + } + } + + nbt.putString("Text", String.join("\n", lines)); } - this.namedTag = nbt; } @Override @@ -39,27 +51,8 @@ public boolean isBlockEntityValid() { return blockID == Block.SIGN_POST || blockID == Block.WALL_SIGN; } - public boolean setText() { - return this.setText(""); - } - - public boolean setText(String line1) { - return this.setText(line1, ""); - } - - public boolean setText(String line1, String line2) { - return this.setText(line1, line2, ""); - } - - public boolean setText(String line1, String line2, String line3) { - return this.setText(line1, line2, line3, ""); - } - - public boolean setText(String line1, String line2, String line3, String line4) { - this.namedTag.putString("Text1", line1); - this.namedTag.putString("Text2", line2); - this.namedTag.putString("Text3", line3); - this.namedTag.putString("Text4", line4); + public boolean setText(String... lines) { + this.namedTag.putString("Text", String.join("\n", lines)); this.spawnToAll(); if (this.chunk != null) { @@ -71,26 +64,46 @@ public boolean setText(String line1, String line2, String line3, String line4) { } public String[] getText() { - return new String[]{ - this.namedTag.getString("Text1"), - this.namedTag.getString("Text2"), - this.namedTag.getString("Text3"), - this.namedTag.getString("Text4") - }; + return this.namedTag.getString("Text").split("\n"); + } + + @Override + public boolean updateCompoundTag(CompoundTag nbt, Player player) { + if (!nbt.getString("id").equals(BlockEntity.SIGN)) { + return false; + } + String[] text = nbt.getString("Text").split("\n", 4); + + SignChangeEvent signChangeEvent = new SignChangeEvent(this.getBlock(), player, text); + + if (!this.namedTag.contains("Creator") || !Objects.equals(player.getUniqueId().toString(), this.namedTag.getString("Creator"))) { + signChangeEvent.setCancelled(); + } + + if (player.getRemoveFormat()) { + for (int i = 0; i < text.length; i++) { + text[i] = TextFormat.clean(text[i]); + } + } + + this.server.getPluginManager().callEvent(signChangeEvent); + + if (!signChangeEvent.isCancelled()) { + this.setText(signChangeEvent.getLines()); + return true; + } + + return false; } @Override public CompoundTag getSpawnCompound() { return new CompoundTag() .putString("id", BlockEntity.SIGN) - .putString("Text1", this.namedTag.getString("Text1")) - .putString("Text2", this.namedTag.getString("Text2")) - .putString("Text3", this.namedTag.getString("Text3")) - .putString("Text4", this.namedTag.getString("Text4")) + .putString("Text", this.namedTag.getString("Text")) .putInt("x", (int) this.x) .putInt("y", (int) this.y) .putInt("z", (int) this.z); } - } diff --git a/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java b/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java index 5371b9655d..1f9b7ee3ad 100644 --- a/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java +++ b/src/main/java/cn/nukkit/blockentity/BlockEntitySpawnable.java @@ -50,4 +50,14 @@ public void spawnToAll() { } } } + + /** + * Called when a player updates a block entity's NBT data + * for example when writing on a sign. + * + * @return bool indication of success, will respawn the tile to the player if false. + */ + public boolean updateCompoundTag(CompoundTag nbt, Player player) { + return false; + } } diff --git a/src/main/java/cn/nukkit/command/Command.java b/src/main/java/cn/nukkit/command/Command.java index 7294aff141..d94283a2d7 100644 --- a/src/main/java/cn/nukkit/command/Command.java +++ b/src/main/java/cn/nukkit/command/Command.java @@ -151,7 +151,7 @@ public boolean testPermission(CommandSender target) { } if (this.permissionMessage == null) { - target.sendMessage(new TranslationContainer(TextFormat.RED + "%commands.generic.permission")); + target.sendMessage(new TranslationContainer(TextFormat.RED + "%commands.generic.unknown", this.name)); } else if (!this.permissionMessage.equals("")) { target.sendMessage(this.permissionMessage.replace("", this.permission)); } diff --git a/src/main/java/cn/nukkit/command/CommandReader.java b/src/main/java/cn/nukkit/command/CommandReader.java index 037750dbee..4586c6ce5c 100644 --- a/src/main/java/cn/nukkit/command/CommandReader.java +++ b/src/main/java/cn/nukkit/command/CommandReader.java @@ -37,7 +37,7 @@ public CommandReader() { this.reader = new ConsoleReader(); reader.setPrompt("> "); instance = this; - + reader.addCompleter(new PlayersCompleter()); // Add player TAB completer reader.addCompleter(new CommandsCompleter()); // Add command TAB completer } catch (IOException e) { @@ -54,11 +54,11 @@ public String readLine() { } return null; } - + public void run() { Long lastLine = System.currentTimeMillis(); String line; - + try { while ((line = reader.readLine()) != null) { if (Server.getInstance().getConsoleSender() == null || Server.getInstance().getPluginManager() == null) { diff --git a/src/main/java/cn/nukkit/command/data/CommandParameter.java b/src/main/java/cn/nukkit/command/data/CommandParameter.java index 281115bab6..a3fe91c979 100644 --- a/src/main/java/cn/nukkit/command/data/CommandParameter.java +++ b/src/main/java/cn/nukkit/command/data/CommandParameter.java @@ -41,25 +41,25 @@ public CommandParameter(String name) { this(name, false); } - public CommandParameter(String name, boolean optional, String enumType){ + public CommandParameter(String name, boolean optional, String enumType) { this.name = name; this.type = ARG_TYPE_STRING_ENUM; this.optional = optional; this.enum_type = enumType; } - public CommandParameter(String name, boolean optional, String[] enumValues){ + public CommandParameter(String name, boolean optional, String[] enumValues) { this.name = name; this.type = ARG_TYPE_STRING_ENUM; this.optional = optional; this.enum_values = enumValues; } - public CommandParameter(String name, String enumType){ + public CommandParameter(String name, String enumType) { this(name, false, enumType); } - public CommandParameter(String name, String[] enumValues){ + public CommandParameter(String name, String[] enumValues) { this(name, false, enumValues); } diff --git a/src/main/java/cn/nukkit/command/defaults/DeopCommand.java b/src/main/java/cn/nukkit/command/defaults/DeopCommand.java index 4bc71c98fa..d87544af85 100644 --- a/src/main/java/cn/nukkit/command/defaults/DeopCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/DeopCommand.java @@ -14,7 +14,7 @@ */ public class DeopCommand extends VanillaCommand { public DeopCommand(String name) { - super(name, "%nukkit.command.deop.description", "%commands.deop.usage"); + super(name, "%nukkit.command.deop.description", "%commands.deop.description"); this.setPermission("nukkit.command.op.take"); this.commandParameters.put("default", new CommandParameter[]{ new CommandParameter("player", CommandParameter.ARG_TYPE_TARGET, false) @@ -38,7 +38,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) player.setOp(false); if (player instanceof Player) { - ((Player) player).sendMessage(TextFormat.GRAY + "You are no longer op!"); + ((Player) player).sendMessage(new TranslationContainer(TextFormat.GRAY + "%commands.deop.message")); } Command.broadcastCommandMessage(sender, new TranslationContainer("commands.deop.success", new String[]{player.getName()})); diff --git a/src/main/java/cn/nukkit/command/defaults/DifficultyCommand.java b/src/main/java/cn/nukkit/command/defaults/DifficultyCommand.java index d2c75f1d6d..40d6800748 100644 --- a/src/main/java/cn/nukkit/command/defaults/DifficultyCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/DifficultyCommand.java @@ -24,7 +24,7 @@ public DifficultyCommand(String name) { }); this.commandParameters.put("byString", new CommandParameter[]{ new CommandParameter("difficulty", new String[]{"peaceful", "p", "easy", "e", - "normal", "n", "hard", "h"}) + "normal", "n", "hard", "h"}) }); } diff --git a/src/main/java/cn/nukkit/command/defaults/EnchantCommand.java b/src/main/java/cn/nukkit/command/defaults/EnchantCommand.java index 0ae775b8de..868f23c44c 100644 --- a/src/main/java/cn/nukkit/command/defaults/EnchantCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/EnchantCommand.java @@ -71,7 +71,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) } public int getIdByName(String value) throws NumberFormatException { - switch (value){ + switch (value) { case "protection": return 0; case "fire_protection": diff --git a/src/main/java/cn/nukkit/command/defaults/OpCommand.java b/src/main/java/cn/nukkit/command/defaults/OpCommand.java index df0dc5c256..8e74af6316 100644 --- a/src/main/java/cn/nukkit/command/defaults/OpCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/OpCommand.java @@ -15,7 +15,7 @@ public class OpCommand extends VanillaCommand { public OpCommand(String name) { - super(name, "%nukkit.command.op.description", "%commands.op.usage"); + super(name, "%nukkit.command.op.description", "%commands.op.description"); this.setPermission("nukkit.command.op.give"); this.commandParameters.clear(); this.commandParameters.put("default", new CommandParameter[]{ @@ -38,7 +38,7 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) Command.broadcastCommandMessage(sender, new TranslationContainer("commands.op.success", player.getName())); if (player instanceof Player) { - ((Player) player).sendMessage(TextFormat.GRAY + "You are now op!"); + ((Player) player).sendMessage(new TranslationContainer(TextFormat.GRAY + "%commands.op.message")); } player.setOp(true); diff --git a/src/main/java/cn/nukkit/command/defaults/SetWorldSpawnCommand.java b/src/main/java/cn/nukkit/command/defaults/SetWorldSpawnCommand.java index ade4f51260..879e38371d 100644 --- a/src/main/java/cn/nukkit/command/defaults/SetWorldSpawnCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/SetWorldSpawnCommand.java @@ -20,7 +20,7 @@ public SetWorldSpawnCommand(String name) { this.setPermission("nukkit.command.setworldspawn"); this.commandParameters.clear(); this.commandParameters.put("default", new CommandParameter[]{ - new CommandParameter("pos", CommandParameter.ARG_TYPE_BLOCK_POS, true) + new CommandParameter("blockPos", CommandParameter.ARG_TYPE_BLOCK_POS, true) }); } diff --git a/src/main/java/cn/nukkit/command/defaults/SpawnpointCommand.java b/src/main/java/cn/nukkit/command/defaults/SpawnpointCommand.java index 04fdaaab6c..ca97b11d6c 100644 --- a/src/main/java/cn/nukkit/command/defaults/SpawnpointCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/SpawnpointCommand.java @@ -21,7 +21,7 @@ public SpawnpointCommand(String name) { this.setPermission("nukkit.command.spawnpoint"); this.commandParameters.clear(); this.commandParameters.put("default", new CommandParameter[]{ - new CommandParameter("pos", CommandParameter.ARG_TYPE_BLOCK_POS, true), + new CommandParameter("blockPos", CommandParameter.ARG_TYPE_BLOCK_POS, true), }); } diff --git a/src/main/java/cn/nukkit/command/defaults/TeleportCommand.java b/src/main/java/cn/nukkit/command/defaults/TeleportCommand.java index 4bbcb30d84..5fba764991 100644 --- a/src/main/java/cn/nukkit/command/defaults/TeleportCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/TeleportCommand.java @@ -28,10 +28,10 @@ public TeleportCommand(String name) { }); this.commandParameters.put("Player->Pos", new CommandParameter[]{ new CommandParameter("player", CommandParameter.ARG_TYPE_TARGET, false), - new CommandParameter("pos", CommandParameter.ARG_TYPE_BLOCK_POS, false), + new CommandParameter("blockPos", CommandParameter.ARG_TYPE_BLOCK_POS, false), }); this.commandParameters.put("->Pos", new CommandParameter[]{ - new CommandParameter("pos", CommandParameter.ARG_TYPE_BLOCK_POS, false), + new CommandParameter("blockPos", CommandParameter.ARG_TYPE_BLOCK_POS, false), }); } diff --git a/src/main/java/cn/nukkit/command/defaults/TitleCommand.java b/src/main/java/cn/nukkit/command/defaults/TitleCommand.java index 732fb77129..ab09ce5d13 100644 --- a/src/main/java/cn/nukkit/command/defaults/TitleCommand.java +++ b/src/main/java/cn/nukkit/command/defaults/TitleCommand.java @@ -78,20 +78,20 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) sender.sendMessage(new TranslationContainer("commands.generic.usage", this.usageMessage)); return false; } - } else if (args.length == 3){ + } else if (args.length == 3) { switch (args[1].toLowerCase()) { case "title": player.sendTitle(args[2]); sender.sendMessage(new TranslationContainer("nukkit.command.title.title", new String[]{TextFormat.clean(args[2]), player.getName()})); break; - case "subtitle": + /*case "subtitle": player.setSubtitle(args[2]); sender.sendMessage(new TranslationContainer("nukkit.command.title.subtitle", new String[]{TextFormat.clean(args[2]), player.getName()})); break; case "actionbar": player.sendActionBarTitle(args[2]); sender.sendMessage(new TranslationContainer("nukkit.command.title.actionbar", new String[]{TextFormat.clean(args[2]), player.getName()})); - break; + break;*/ default: sender.sendMessage(new TranslationContainer("commands.generic.usage", this.usageMessage)); return false; @@ -99,9 +99,9 @@ public boolean execute(CommandSender sender, String commandLabel, String[] args) } else if (args.length == 5) { if (args[1].toLowerCase().equals("times")) { try { - player.setTitleAnimationTimes(Integer.valueOf(args[2]), //fadeIn + /*player.setTitleAnimationTimes(Integer.valueOf(args[2]), //fadeIn Integer.valueOf(args[3]), //stay - Integer.valueOf(args[4])); //fadeOut + Integer.valueOf(args[4])); //fadeOut*/ sender.sendMessage(new TranslationContainer("nukkit.command.title.times.success", new String[]{ args[2], args[3], args[4], player.getName()})); } catch (NumberFormatException exception) { diff --git a/src/main/java/cn/nukkit/entity/Entity.java b/src/main/java/cn/nukkit/entity/Entity.java index 7deed970e6..ac6a907f99 100644 --- a/src/main/java/cn/nukkit/entity/Entity.java +++ b/src/main/java/cn/nukkit/entity/Entity.java @@ -8,6 +8,7 @@ import cn.nukkit.block.BlockWater; import cn.nukkit.entity.data.*; import cn.nukkit.entity.item.EntityVehicle; +import cn.nukkit.event.Event; import cn.nukkit.event.entity.*; import cn.nukkit.event.entity.EntityDamageEvent.DamageCause; import cn.nukkit.event.entity.EntityPortalEnterEvent.PortalType; @@ -70,7 +71,7 @@ public abstract class Entity extends Location implements Metadatable { public static final int DATA_AIR = 7; //short public static final int DATA_POTION_COLOR = 8; //int (ARGB!) public static final int DATA_POTION_AMBIENT = 9; //byte - /* 10 (byte) */ + public static final int DATA_JUMP_DURATION = 10; //long public static final int DATA_HURT_TIME = 11; //int (minecart/boat) public static final int DATA_HURT_DIRECTION = 12; //int (minecart/boat) public static final int DATA_PADDLE_TIME_LEFT = 13; //float @@ -83,9 +84,9 @@ public abstract class Entity extends Location implements Metadatable { public static final int DATA_ENDERMAN_HELD_ITEM_ID = 23; //short public static final int DATA_ENDERMAN_HELD_ITEM_DAMAGE = 24; //short public static final int DATA_ENTITY_AGE = 25; //short - /* 27 (byte) player-specific flags - * 28 (int) player "index"? - * 29 (block coords) bed position */ + public static final int DATA_PLAYER_FLAGS = 29; //byte + /* 28 (int) player "index"? */ + public static final int DATA_PLAYER_BED_POSITION = 29; //block coords public static final int DATA_FIREBALL_POWER_X = 30; //float public static final int DATA_FIREBALL_POWER_Y = 31; public static final int DATA_FIREBALL_POWER_Z = 32; @@ -104,6 +105,7 @@ public abstract class Entity extends Location implements Metadatable { /* 45 (byte) container stuff * 46 (int) container stuff * 47 (int) container stuff */ + public static final int DATA_FLAG_FIRE_IMMUNE = 47; public static final int DATA_BLOCK_TARGET = 48; //block coords (ender crystal) public static final int DATA_WITHER_INVULNERABLE_TICKS = 49; //int public static final int DATA_WITHER_TARGET_1 = 50; //long @@ -145,7 +147,7 @@ public abstract class Entity extends Location implements Metadatable { public static final int DATA_FLAG_SADDLED = 8; public static final int DATA_FLAG_POWERED = 9; public static final int DATA_FLAG_IGNITED = 10; - public static final int DATA_FLAG_BABY = 11; + public static final int DATA_FLAG_BABY = 11; //disable head scaling public static final int DATA_FLAG_CONVERTING = 12; public static final int DATA_FLAG_CRITICAL = 13; public static final int DATA_FLAG_CAN_SHOW_NAMETAG = 14; @@ -176,7 +178,10 @@ public abstract class Entity extends Location implements Metadatable { public static final int DATA_FLAG_IDLING = 39; public static final int DATA_FLAG_EVOKER_SPELL = 40; public static final int DATA_FLAG_CHARGE_ATTACK = 41; + public static final int DATA_FLAG_WASD_CONTROLLED = 43; + public static final int DATA_FLAG_CAN_POWER_JUMP = 44; public static final int DATA_FLAG_LINGER = 45; + public static final int DATA_FLAG_GRAVITY = 46; public static long entityCount = 1; @@ -205,8 +210,8 @@ public abstract class Entity extends Location implements Metadatable { protected EntityDamageEvent lastDamageCause = null; - protected List blocksAround = new ArrayList<>(); - protected List collisionBlocks = new ArrayList<>(); + public List blocksAround = new ArrayList<>(); + public List collisionBlocks = new ArrayList<>(); public double lastX; public double lastY; @@ -241,6 +246,8 @@ public abstract class Entity extends Location implements Metadatable { protected float health = 20; private int maxHealth = 20; + protected float absorption = 0; + protected float ySize = 0; public boolean keepMovement = false; @@ -854,6 +861,11 @@ public boolean attack(EntityDamageEvent source) { if (source.isCancelled()) { return false; } + if (this.absorption > 0) { //Damage Absorption + float absorptionHealth = this.absorption - source.getFinalDamage() > 0 ? source.getFinalDamage() : this.absorption; + this.setAbsorption(this.absorption - absorptionHealth); + source.setDamage(-absorptionHealth, EntityDamageEvent.DamageModifier.ABSORPTION); + } setLastDamageCause(source); setHealth(getHealth() - source.getFinalDamage()); return true; @@ -1036,8 +1048,8 @@ public boolean entityBaseTick(int tickDiff) { Timings.entityBaseTickTimer.stopTiming(); return false; } - if (riding != null && !riding.isAlive()) { - ((EntityVehicle) riding).mountEntity(this); + if (riding != null && !riding.isAlive() && riding instanceof EntityRideable) { + ((EntityRideable) riding).mountEntity(this); } if (!this.effects.isEmpty()) { @@ -1092,7 +1104,7 @@ public boolean entityBaseTick(int tickDiff) { if (this.inPortalTicks == 80) { EntityPortalEnterEvent ev = new EntityPortalEnterEvent(this, PortalType.NETHER); getServer().getPluginManager().callEvent(ev); - + //TODO: teleport } @@ -1251,6 +1263,17 @@ public void setOnFire(int seconds) { } } + public float getAbsorption() { + return absorption; + } + + public void setAbsorption(float absorption) { + if (absorption != this.absorption) { + this.absorption = absorption; + if (this instanceof Player) ((Player) this).setAttribute(Attribute.getAttribute(Attribute.ABSORPTION).setValue(absorption)); + } + } + public BlockFace getDirection() { double rotation = this.yaw % 360; if (rotation < 0) { @@ -1309,13 +1332,17 @@ public void fall(float fallDistance) { Block down = this.level.getBlock(this.floor().down()); if (down.getId() == Item.FARMLAND) { + Event ev; + if (this instanceof Player) { - Player p = (Player) this; - PlayerInteractEvent ev = new PlayerInteractEvent(p, p.getInventory().getItemInHand(), down, null, Action.PHYSICAL); - this.server.getPluginManager().callEvent(ev); - if (ev.isCancelled()) { - return; - } + ev = new PlayerInteractEvent((Player) this, null, down, null, Action.PHYSICAL); + } else { + ev = new EntityInteractEvent(this, down); + } + + this.server.getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + return; } this.level.setBlock(down, new BlockDirt(), true, true); } @@ -1701,7 +1728,7 @@ public void setRotation(double yaw, double pitch) { * used for bat only */ public boolean doesTriggerPressurePlate() { - return false; + return true; } protected void checkChunks() { diff --git a/src/main/java/cn/nukkit/entity/EntityHuman.java b/src/main/java/cn/nukkit/entity/EntityHuman.java index ed50f2ff5b..0fef9b4728 100644 --- a/src/main/java/cn/nukkit/entity/EntityHuman.java +++ b/src/main/java/cn/nukkit/entity/EntityHuman.java @@ -22,7 +22,8 @@ public class EntityHuman extends EntityHumanType { public static final int DATA_PLAYER_FLAG_DEAD = 2; //TODO: CHECK public static final int DATA_PLAYER_FLAGS = 27; - public static final int DATA_PLAYER_BED_POSITION = 17; + + public static final int DATA_PLAYER_BED_POSITION = 29; public static final int DATA_PLAYER_BUTTON_TEXT = 40; protected UUID uuid; @@ -83,6 +84,7 @@ public void setSkin(Skin skin) { @Override protected void initEntity() { this.setDataFlag(DATA_PLAYER_FLAGS, DATA_PLAYER_FLAG_SLEEP, false); + this.setDataFlag(DATA_FLAGS, DATA_FLAG_GRAVITY); this.setDataProperty(new IntPositionEntityData(DATA_PLAYER_BED_POSITION, 0, 0, 0), false); @@ -103,10 +105,6 @@ protected void initEntity() { } super.initEntity(); - - if (this instanceof Player) { - ((Player) this).addWindow(this.inventory, 0); - } } @Override @@ -135,7 +133,10 @@ public void spawnTo(Player player) { throw new IllegalStateException(this.getClass().getSimpleName() + " must have a valid skin set"); } - this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getName(), this.skin, new Player[]{player}); + if (this instanceof Player) + this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getName(), this.skin, ((Player) this).getLoginChainData().getXUID(), new Player[]{player}); + else + this.server.updatePlayerListData(this.getUniqueId(), this.getId(), this.getName(), this.skin, new Player[]{player}); AddPlayerPacket pk = new AddPlayerPacket(); pk.uuid = this.getUniqueId(); diff --git a/src/main/java/cn/nukkit/entity/EntityHumanType.java b/src/main/java/cn/nukkit/entity/EntityHumanType.java index 215a7d5e04..a85d2cc764 100644 --- a/src/main/java/cn/nukkit/entity/EntityHumanType.java +++ b/src/main/java/cn/nukkit/entity/EntityHumanType.java @@ -45,8 +45,9 @@ protected void initEntity() { ListTag inventoryList = this.namedTag.getList("Inventory", CompoundTag.class); for (CompoundTag item : inventoryList.getAll()) { int slot = item.getByte("Slot"); - if (slot >= 0 && slot < 9) { - this.inventory.setHotbarSlotIndex(slot, item.contains("TrueSlot") ? item.getByte("TrueSlot") : -1); + if (slot >= 0 && slot < 9) { //hotbar + //Old hotbar saving stuff, remove it (useless now) + inventoryList.remove(item); } else if (slot >= 100 && slot < 104) { this.inventory.setItem(this.inventory.getSize() + slot - 100, NBTIO.getItemHelper(item)); } else { @@ -74,14 +75,6 @@ public void saveNBT() { this.namedTag.putList(new ListTag("Inventory")); if (this.inventory != null) { for (int slot = 0; slot < 9; ++slot) { - int hotbarSlot = this.inventory.getHotbarSlotIndex(slot); - if (hotbarSlot != -1) { - Item item = this.inventory.getItem(hotbarSlot); - if (item.getId() != 0 && item.getCount() > 0) { - this.namedTag.getList("Inventory", CompoundTag.class).add(NBTIO.putItemHelper(item, slot).putByte("TrueSlot", hotbarSlot)); - continue; - } - } this.namedTag.getList("Inventory", CompoundTag.class).add(new CompoundTag() .putByte("Count", 0) .putShort("Damage", 0) diff --git a/src/main/java/cn/nukkit/entity/EntityInteractable.java b/src/main/java/cn/nukkit/entity/EntityInteractable.java index 22a44e01e4..49c9515a1a 100644 --- a/src/main/java/cn/nukkit/entity/EntityInteractable.java +++ b/src/main/java/cn/nukkit/entity/EntityInteractable.java @@ -1,20 +1,13 @@ package cn.nukkit.entity; -import cn.nukkit.level.format.FullChunk; -import cn.nukkit.nbt.tag.CompoundTag; - /** * @author Adam Matthew */ -public abstract class EntityInteractable extends Entity { - - public EntityInteractable(FullChunk chunk, CompoundTag nbt) { - super(chunk, nbt); - } +public interface EntityInteractable { // Todo: Passive entity?? i18n and boat leaving text - public abstract String getInteractButtonText(); + String getInteractButtonText(); - public abstract boolean canDoInteraction(); + boolean canDoInteraction(); } diff --git a/src/main/java/cn/nukkit/entity/EntityLiving.java b/src/main/java/cn/nukkit/entity/EntityLiving.java index 932baed7ff..5f30e58155 100644 --- a/src/main/java/cn/nukkit/entity/EntityLiving.java +++ b/src/main/java/cn/nukkit/entity/EntityLiving.java @@ -88,7 +88,7 @@ public boolean hasLineOfSight(Entity entity) { return true; } - public void collidingWith(EntityVehicle ent) { // can override (IronGolem|Bats) + public void collidingWith(Entity ent) { // can override (IronGolem|Bats) ent.applyEntityCollision(this); } @@ -239,8 +239,8 @@ public boolean entityBaseTick(int tickDiff) { } if (this.riding == null) { for (Entity entity : level.getNearbyEntities(this.boundingBox.grow(0.20000000298023224D, 0.0D, 0.20000000298023224D), this)) { - if (entity instanceof EntityVehicle) { - this.collidingWith((EntityVehicle) entity); + if (entity instanceof EntityRideable) { + this.collidingWith(entity); } } } @@ -340,9 +340,4 @@ public void setMovementSpeed(float speed) { public float getMovementSpeed() { return this.movementSpeed; } - - @Override - public boolean doesTriggerPressurePlate() { - return true; - } } diff --git a/src/main/java/cn/nukkit/entity/EntityRideable.java b/src/main/java/cn/nukkit/entity/EntityRideable.java index 70b5b8f20d..91441f8dea 100644 --- a/src/main/java/cn/nukkit/entity/EntityRideable.java +++ b/src/main/java/cn/nukkit/entity/EntityRideable.java @@ -5,4 +5,13 @@ * Nukkit Project */ public interface EntityRideable { + + /** + * Mount or Dismounts an Entity from a rideable entity + * + * @param entity The target Entity + * @return {@code true} if the mounting successful + */ + boolean mountEntity(Entity entity); + } diff --git a/src/main/java/cn/nukkit/entity/data/Skin.java b/src/main/java/cn/nukkit/entity/data/Skin.java index c2ba8dfd0f..d6e4b1772d 100644 --- a/src/main/java/cn/nukkit/entity/data/Skin.java +++ b/src/main/java/cn/nukkit/entity/data/Skin.java @@ -25,6 +25,7 @@ public class Skin { private byte[] data = new byte[SINGLE_SKIN_SIZE]; private String model; + private Cape cape = new Cape(new byte[0]); //default no cape public Skin(byte[] data) { this(data, MODEL_STEVE); @@ -150,7 +151,96 @@ public void setModel(String model) { this.model = model; } + public Cape getCape() { + return cape; + } + + public void setCape(Cape cape) { + this.cape = cape; + } + public boolean isValid() { return this.data.length == SINGLE_SKIN_SIZE || this.data.length == DOUBLE_SKIN_SIZE; } + + public class Cape { + + public byte[] data; + + public Cape(byte[] data) { + this.setData(data); + } + + public Cape(InputStream inputStream) { + BufferedImage image; + try { + image = ImageIO.read(inputStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + + this.parseBufferedImage(image); + } + + public Cape(ImageInputStream inputStream) { + BufferedImage image; + try { + image = ImageIO.read(inputStream); + } catch (IOException e) { + throw new RuntimeException(e); + } + this.parseBufferedImage(image); + } + + public Cape(File file, String model) { + BufferedImage image; + try { + image = ImageIO.read(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + this.parseBufferedImage(image); + } + + public Cape(URL url) { + BufferedImage image; + try { + image = ImageIO.read(url); + } catch (IOException e) { + throw new RuntimeException(e); + } + this.parseBufferedImage(image); + } + + public Cape(BufferedImage image) { + this.parseBufferedImage(image); + } + + public Cape(String base64) { + this(Base64.getDecoder().decode(base64)); + } + + public void setData(byte[] data) { + this.data = data; + } + + public byte[] getData() { + return data; + } + + public void parseBufferedImage(BufferedImage image) { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + for (int y = 0; y < image.getHeight(); y++) { + for (int x = 0; x < image.getWidth(); x++) { + Color color = new Color(image.getRGB(x, y), true); + outputStream.write(color.getRed()); + outputStream.write(color.getGreen()); + outputStream.write(color.getBlue()); + outputStream.write(color.getAlpha()); + } + } + image.flush(); + this.setData(outputStream.toByteArray()); + } + } } diff --git a/src/main/java/cn/nukkit/entity/item/EntityBoat.java b/src/main/java/cn/nukkit/entity/item/EntityBoat.java index a28e3209d2..8c940db809 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityBoat.java +++ b/src/main/java/cn/nukkit/entity/item/EntityBoat.java @@ -4,6 +4,8 @@ import cn.nukkit.entity.Entity; import cn.nukkit.event.entity.EntityDamageByEntityEvent; import cn.nukkit.event.entity.EntityDamageEvent; +import cn.nukkit.event.vehicle.VehicleDamageEvent; +import cn.nukkit.event.vehicle.VehicleDestroyEvent; import cn.nukkit.event.vehicle.VehicleMoveEvent; import cn.nukkit.event.vehicle.VehicleUpdateEvent; import cn.nukkit.item.Item; @@ -93,11 +95,30 @@ public boolean attack(EntityDamageEvent source) { if (invulnerable) { return false; } else { - performHurtAnimation((int) source.getFinalDamage()); + // Event start + VehicleDamageEvent event = new VehicleDamageEvent(this, source.getEntity(), source.getFinalDamage()); + getServer().getPluginManager().callEvent(event); + if (event.isCancelled()) { + return false; + } + // Event stop + performHurtAnimation((int) event.getDamage()); + + boolean instantKill = false; + + if (source instanceof EntityDamageByEntityEvent) { + Entity damager = ((EntityDamageByEntityEvent) source).getDamager(); + instantKill = damager instanceof Player && ((Player) damager).isCreative(); + } - Entity damager = ((EntityDamageByEntityEvent) source).getDamager(); - boolean instantKill = damager instanceof Player && ((Player) damager).isCreative(); if (instantKill || getDamage() > 40) { + // Event start + VehicleDestroyEvent event2 = new VehicleDestroyEvent(this, source.getEntity()); + getServer().getPluginManager().callEvent(event2); + if (event2.isCancelled()) { + return false; + } + // Event stop if (linkedEntity != null) { mountEntity(linkedEntity); } diff --git a/src/main/java/cn/nukkit/entity/item/EntityItem.java b/src/main/java/cn/nukkit/entity/item/EntityItem.java index 9dbd8a31fc..4fbca75fa9 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityItem.java +++ b/src/main/java/cn/nukkit/entity/item/EntityItem.java @@ -100,6 +100,7 @@ protected void initEntity() { } this.item = NBTIO.getItemHelper(this.namedTag.getCompound("Item")); + this.setDataFlag(DATA_FLAGS, DATA_FLAG_IMMOBILE, true); this.server.getPluginManager().callEvent(new ItemSpawnEvent(this)); } @@ -262,4 +263,9 @@ public void spawnTo(Player player) { super.spawnTo(player); } + + @Override + public boolean doesTriggerPressurePlate() { + return true; + } } diff --git a/src/main/java/cn/nukkit/entity/item/EntityVehicle.java b/src/main/java/cn/nukkit/entity/item/EntityVehicle.java index 74ab837635..1edfe83d18 100644 --- a/src/main/java/cn/nukkit/entity/item/EntityVehicle.java +++ b/src/main/java/cn/nukkit/entity/item/EntityVehicle.java @@ -18,7 +18,7 @@ * author: MagicDroidX * Nukkit Project */ -public abstract class EntityVehicle extends EntityInteractable implements EntityRideable { +public abstract class EntityVehicle extends Entity implements EntityRideable, EntityInteractable { public EntityVehicle(FullChunk chunk, CompoundTag nbt) { super(chunk, nbt); @@ -64,6 +64,7 @@ public boolean canDoInteraction() { * @param entity The target Entity * @return {@code true} if the mounting successful */ + @Override public boolean mountEntity(Entity entity) { Objects.requireNonNull(entity, "The target of the mounting entity can't be null"); this.PitchDelta = 0.0D; diff --git a/src/main/java/cn/nukkit/entity/weather/EntityLightning.java b/src/main/java/cn/nukkit/entity/weather/EntityLightning.java index 1883f807f3..30fba34e45 100644 --- a/src/main/java/cn/nukkit/entity/weather/EntityLightning.java +++ b/src/main/java/cn/nukkit/entity/weather/EntityLightning.java @@ -119,8 +119,8 @@ public boolean onUpdate(int currentTick) { this.entityBaseTick(tickDiff); if (this.state == 2) { - this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_THUNDER, 93, -1, this, false, false); - this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_EXPLODE, 93, -1, this, false, false); + this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_THUNDER, 93, -1, this); + this.level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_EXPLODE, 93, -1, this); } this.state--; diff --git a/src/main/java/cn/nukkit/event/block/BlockPistonChangeEvent.java b/src/main/java/cn/nukkit/event/block/BlockPistonChangeEvent.java new file mode 100644 index 0000000000..ab5d0184f0 --- /dev/null +++ b/src/main/java/cn/nukkit/event/block/BlockPistonChangeEvent.java @@ -0,0 +1,33 @@ +package cn.nukkit.event.block; + +import cn.nukkit.block.Block; +import cn.nukkit.event.HandlerList; + +/** + * Created by CreeperFace on 2.8.2017. + */ +public class BlockPistonChangeEvent extends BlockEvent { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private int oldPower; + private int newPower; + + public BlockPistonChangeEvent(Block block, int oldPower, int newPower) { + super(block); + this.oldPower = oldPower; + this.newPower = newPower; + } + + public int getOldPower() { + return oldPower; + } + + public int getNewPower() { + return newPower; + } +} diff --git a/src/main/java/cn/nukkit/event/entity/EntityDamageEvent.java b/src/main/java/cn/nukkit/event/entity/EntityDamageEvent.java index c2a00e67a3..3652869819 100644 --- a/src/main/java/cn/nukkit/event/entity/EntityDamageEvent.java +++ b/src/main/java/cn/nukkit/event/entity/EntityDamageEvent.java @@ -120,7 +120,11 @@ public enum DamageModifier { /** * Damage reduction caused by the Resistance potion effect */ - RESISTANCE + RESISTANCE, + /** + * Damage reduction caused by the Damage absorption effect + */ + ABSORPTION //ARMOR_ENCHANTMENTS } diff --git a/src/main/java/cn/nukkit/event/entity/EntityInteractEvent.java b/src/main/java/cn/nukkit/event/entity/EntityInteractEvent.java new file mode 100644 index 0000000000..5d198f2e9c --- /dev/null +++ b/src/main/java/cn/nukkit/event/entity/EntityInteractEvent.java @@ -0,0 +1,29 @@ +package cn.nukkit.event.entity; + +import cn.nukkit.block.Block; +import cn.nukkit.entity.Entity; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; + +/** + * @author CreeperFace + */ +public class EntityInteractEvent extends EntityEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private Block block; + + public EntityInteractEvent(Entity entity, Block block) { + this.entity = entity; + this.block = block; + } + + public Block getBlock() { + return block; + } +} diff --git a/src/main/java/cn/nukkit/event/entity/EntityVehicleEnterEvent.java b/src/main/java/cn/nukkit/event/entity/EntityVehicleEnterEvent.java index 12dfe408b7..0a3b505cc4 100644 --- a/src/main/java/cn/nukkit/event/entity/EntityVehicleEnterEvent.java +++ b/src/main/java/cn/nukkit/event/entity/EntityVehicleEnterEvent.java @@ -12,7 +12,7 @@ public class EntityVehicleEnterEvent extends EntityEvent implements Cancellable public static HandlerList getHandlers() { return handlers; } - + private final EntityVehicle vehicle; public EntityVehicleEnterEvent(Entity entity, EntityVehicle vehicle) { diff --git a/src/main/java/cn/nukkit/event/inventory/BrewEvent.java b/src/main/java/cn/nukkit/event/inventory/BrewEvent.java new file mode 100644 index 0000000000..e00a225aaa --- /dev/null +++ b/src/main/java/cn/nukkit/event/inventory/BrewEvent.java @@ -0,0 +1,59 @@ +package cn.nukkit.event.inventory; + +import cn.nukkit.blockentity.BlockEntityBrewingStand; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.item.Item; + +/** + * @author CreeperFace + */ +public class BrewEvent extends InventoryEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final BlockEntityBrewingStand brewingStand; + private final Item ingredient; + private final Item[] potions; + private final int fuel; + + public BrewEvent(BlockEntityBrewingStand blockEntity) { + super(blockEntity.getInventory()); + this.brewingStand = blockEntity; + this.fuel = blockEntity.fuelAmount; + + this.ingredient = blockEntity.getInventory().getIngredient(); + + this.potions = new Item[3]; + for (int i = 0; i < 3; i++) { + this.potions[i] = blockEntity.getInventory().getItem(i); + } + } + + public BlockEntityBrewingStand getBrewingStand() { + return brewingStand; + } + + public Item getIngredient() { + return ingredient; + } + + public Item[] getPotions() { + return potions; + } + + /** + * @param index Potion index in range 0 - 2 + */ + public Item getPotion(int index) { + return this.potions[index]; + } + + public int getFuel() { + return fuel; + } +} diff --git a/src/main/java/cn/nukkit/event/inventory/InventoryTransactionEvent.java b/src/main/java/cn/nukkit/event/inventory/InventoryTransactionEvent.java index c7d0328afd..c416b726e6 100644 --- a/src/main/java/cn/nukkit/event/inventory/InventoryTransactionEvent.java +++ b/src/main/java/cn/nukkit/event/inventory/InventoryTransactionEvent.java @@ -3,7 +3,7 @@ import cn.nukkit.event.Cancellable; import cn.nukkit.event.Event; import cn.nukkit.event.HandlerList; -import cn.nukkit.inventory.TransactionGroup; +import cn.nukkit.inventory.transaction.InventoryTransaction; /** * author: MagicDroidX @@ -17,14 +17,13 @@ public static HandlerList getHandlers() { return handlers; } - private final TransactionGroup transaction; + private final InventoryTransaction transaction; - public InventoryTransactionEvent(TransactionGroup transaction) { + public InventoryTransactionEvent(InventoryTransaction transaction) { this.transaction = transaction; } - public TransactionGroup getTransaction() { + public InventoryTransaction getTransaction() { return transaction; } - } \ No newline at end of file diff --git a/src/main/java/cn/nukkit/event/inventory/StartBrewEvent.java b/src/main/java/cn/nukkit/event/inventory/StartBrewEvent.java new file mode 100644 index 0000000000..5ad96b160e --- /dev/null +++ b/src/main/java/cn/nukkit/event/inventory/StartBrewEvent.java @@ -0,0 +1,53 @@ +package cn.nukkit.event.inventory; + +import cn.nukkit.blockentity.BlockEntityBrewingStand; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.item.Item; + +/** + * @author CreeperFace + */ +public class StartBrewEvent extends InventoryEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final BlockEntityBrewingStand brewingStand; + private final Item ingredient; + private final Item[] potions; + + public StartBrewEvent(BlockEntityBrewingStand blockEntity) { + super(blockEntity.getInventory()); + this.brewingStand = blockEntity; + + this.ingredient = blockEntity.getInventory().getIngredient(); + + this.potions = new Item[3]; + for (int i = 0; i < 3; i++) { + this.potions[i] = blockEntity.getInventory().getItem(i); + } + } + + public BlockEntityBrewingStand getBrewingStand() { + return brewingStand; + } + + public Item getIngredient() { + return ingredient; + } + + public Item[] getPotions() { + return potions; + } + + /** + * @param index Potion index in range 0 - 2 + */ + public Item getPotion(int index) { + return this.potions[index]; + } +} diff --git a/src/main/java/cn/nukkit/event/player/PlayerBlockPickEvent.java b/src/main/java/cn/nukkit/event/player/PlayerBlockPickEvent.java new file mode 100644 index 0000000000..bbca5b106e --- /dev/null +++ b/src/main/java/cn/nukkit/event/player/PlayerBlockPickEvent.java @@ -0,0 +1,40 @@ +package cn.nukkit.event.player; + +import cn.nukkit.Player; +import cn.nukkit.block.Block; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.item.Item; + +/** + * @author CreeperFace + */ +public class PlayerBlockPickEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final Block blockClicked; + private Item item; + + public PlayerBlockPickEvent(Player player, Block blockClicked, Item item) { + this.blockClicked = blockClicked; + this.item = item; + this.player = player; + } + + public Item getItem() { + return item; + } + + public void setItem(Item item) { + this.item = item; + } + + public Block getBlockClicked() { + return blockClicked; + } +} diff --git a/src/main/java/cn/nukkit/event/player/PlayerFormRespondedEvent.java b/src/main/java/cn/nukkit/event/player/PlayerFormRespondedEvent.java new file mode 100644 index 0000000000..d3eee72225 --- /dev/null +++ b/src/main/java/cn/nukkit/event/player/PlayerFormRespondedEvent.java @@ -0,0 +1,49 @@ +package cn.nukkit.event.player; + +import cn.nukkit.Player; +import cn.nukkit.event.HandlerList; +import cn.nukkit.form.response.FormResponse; +import cn.nukkit.form.window.FormWindow; + +public class PlayerFormRespondedEvent extends PlayerEvent { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + protected int formID; + protected FormWindow window; + + protected boolean closed = false; + + public PlayerFormRespondedEvent(Player player, int formID, FormWindow window) { + this.player = player; + this.formID = formID; + this.window = window; + } + + public int getFormID() { + return this.formID; + } + + public FormWindow getWindow() { + return window; + } + + /** + * Can be null if player closed the window instead of submitting it + */ + public FormResponse getResponse() { + return window.getResponse(); + } + + /** + * Defines if player closed the window or submitted it + */ + public boolean wasClosed() { + return window.wasClosed(); + } + +} diff --git a/src/main/java/cn/nukkit/event/player/PlayerItemHeldEvent.java b/src/main/java/cn/nukkit/event/player/PlayerItemHeldEvent.java index b64cc57286..c38a17e63b 100644 --- a/src/main/java/cn/nukkit/event/player/PlayerItemHeldEvent.java +++ b/src/main/java/cn/nukkit/event/player/PlayerItemHeldEvent.java @@ -18,22 +18,21 @@ public static HandlerList getHandlers() { } private final Item item; - private final int slot; - private final int inventorySlot; + private final int hotbarSlot; - public PlayerItemHeldEvent(Player player, Item item, int inventorySlot, int slot) { + public PlayerItemHeldEvent(Player player, Item item, int hotbarSlot) { this.player = player; this.item = item; - this.inventorySlot = inventorySlot; - this.slot = slot; + this.hotbarSlot = hotbarSlot; } public int getSlot() { - return slot; + return this.hotbarSlot; } + @Deprecated public int getInventorySlot() { - return inventorySlot; + return hotbarSlot; } public Item getItem() { diff --git a/src/main/java/cn/nukkit/event/player/PlayerMoveEvent.java b/src/main/java/cn/nukkit/event/player/PlayerMoveEvent.java index 60edf4ff41..9dbd77466e 100644 --- a/src/main/java/cn/nukkit/event/player/PlayerMoveEvent.java +++ b/src/main/java/cn/nukkit/event/player/PlayerMoveEvent.java @@ -15,10 +15,17 @@ public static HandlerList getHandlers() { private Location from; private Location to; + private boolean resetBlocksAround; + public PlayerMoveEvent(Player player, Location from, Location to) { + this(player, from, to, true); + } + + public PlayerMoveEvent(Player player, Location from, Location to, boolean resetBlocks) { this.player = player; this.from = from; this.to = to; + this.resetBlocksAround = resetBlocks; } public Location getFrom() { @@ -36,4 +43,17 @@ public Location getTo() { public void setTo(Location to) { this.to = to; } + + public boolean isResetBlocksAround() { + return resetBlocksAround; + } + + public void setResetBlocksAround(boolean value) { + this.resetBlocksAround = value; + } + + @Override + public void setCancelled() { + super.setCancelled(); + } } diff --git a/src/main/java/cn/nukkit/event/player/PlayerServerSettingsRequestEvent.java b/src/main/java/cn/nukkit/event/player/PlayerServerSettingsRequestEvent.java new file mode 100644 index 0000000000..400dd347ed --- /dev/null +++ b/src/main/java/cn/nukkit/event/player/PlayerServerSettingsRequestEvent.java @@ -0,0 +1,39 @@ +package cn.nukkit.event.player; + +import cn.nukkit.Player; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.form.window.FormWindow; + +import java.util.Map; + +/** + * @author CreeperFace + */ +public class PlayerServerSettingsRequestEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private Map settings; + + public PlayerServerSettingsRequestEvent(Player player, Map settings) { + this.player = player; + this.settings = settings; + } + + public Map getSettings() { + return settings; + } + + public void setSettings(Map settings) { + this.settings = settings; + } + + public void setSettings(int id, FormWindow window) { + this.settings.put(id, window); + } +} diff --git a/src/main/java/cn/nukkit/event/player/PlayerSettingsRespondedEvent.java b/src/main/java/cn/nukkit/event/player/PlayerSettingsRespondedEvent.java new file mode 100644 index 0000000000..5743436543 --- /dev/null +++ b/src/main/java/cn/nukkit/event/player/PlayerSettingsRespondedEvent.java @@ -0,0 +1,55 @@ +package cn.nukkit.event.player; + +import cn.nukkit.Player; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; +import cn.nukkit.form.response.FormResponse; +import cn.nukkit.form.window.FormWindow; + +public class PlayerSettingsRespondedEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + protected int formID; + protected FormWindow window; + + protected boolean closed = false; + + public PlayerSettingsRespondedEvent(Player player, int formID, FormWindow window) { + this.player = player; + this.formID = formID; + this.window = window; + } + + public int getFormID() { + return this.formID; + } + + public FormWindow getWindow() { + return window; + } + + /** + * Can be null if player closed the window instead of submitting it + */ + public FormResponse getResponse() { + return window.getResponse(); + } + + /** + * Defines if player closed the window or submitted it + */ + public boolean wasClosed() { + return window.wasClosed(); + } + + @Override + public void setCancelled() { + super.setCancelled(); + } + +} diff --git a/src/main/java/cn/nukkit/event/vehicle/EntityEnterVehicleEvent.java b/src/main/java/cn/nukkit/event/vehicle/EntityEnterVehicleEvent.java new file mode 100644 index 0000000000..a654ec75dc --- /dev/null +++ b/src/main/java/cn/nukkit/event/vehicle/EntityEnterVehicleEvent.java @@ -0,0 +1,32 @@ +package cn.nukkit.event.vehicle; + +import cn.nukkit.Player; +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.item.EntityVehicle; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; + +public class EntityEnterVehicleEvent extends VehicleEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final Entity riding; + + public EntityEnterVehicleEvent(Entity riding, EntityVehicle vehicle) { + super(vehicle); + this.riding = riding; + } + + public Entity getEntity() { + return riding; + } + + public boolean isPlayer() { + return riding instanceof Player; + } + +} diff --git a/src/main/java/cn/nukkit/event/vehicle/EntityExitVehicleEvent.java b/src/main/java/cn/nukkit/event/vehicle/EntityExitVehicleEvent.java new file mode 100644 index 0000000000..39694dd25f --- /dev/null +++ b/src/main/java/cn/nukkit/event/vehicle/EntityExitVehicleEvent.java @@ -0,0 +1,32 @@ +package cn.nukkit.event.vehicle; + +import cn.nukkit.Player; +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.item.EntityVehicle; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; + +public class EntityExitVehicleEvent extends VehicleEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final Entity riding; + + public EntityExitVehicleEvent(Entity riding, EntityVehicle vehicle) { + super(vehicle); + this.riding = riding; + } + + public Entity getEntity() { + return riding; + } + + public boolean isPlayer() { + return riding instanceof Player; + } + +} diff --git a/src/main/java/cn/nukkit/event/vehicle/VehicleCreateEvent.java b/src/main/java/cn/nukkit/event/vehicle/VehicleCreateEvent.java new file mode 100644 index 0000000000..24faa86f03 --- /dev/null +++ b/src/main/java/cn/nukkit/event/vehicle/VehicleCreateEvent.java @@ -0,0 +1,19 @@ +package cn.nukkit.event.vehicle; + +import cn.nukkit.entity.item.EntityVehicle; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; + +public class VehicleCreateEvent extends VehicleEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + public VehicleCreateEvent(EntityVehicle vehicle) { + super(vehicle); + } + +} diff --git a/src/main/java/cn/nukkit/event/vehicle/VehicleDamageEvent.java b/src/main/java/cn/nukkit/event/vehicle/VehicleDamageEvent.java new file mode 100644 index 0000000000..0a673778c6 --- /dev/null +++ b/src/main/java/cn/nukkit/event/vehicle/VehicleDamageEvent.java @@ -0,0 +1,37 @@ +package cn.nukkit.event.vehicle; + +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.item.EntityVehicle; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; + +public class VehicleDamageEvent extends VehicleEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final Entity attacker; + private double damage; + + public VehicleDamageEvent(EntityVehicle vehicle, Entity attacker, double damage) { + super(vehicle); + this.attacker = attacker; + this.damage = damage; + } + + public Entity getAttacker() { + return attacker; + } + + public double getDamage() { + return damage; + } + + public void setDamage(double damage) { + this.damage = damage; + } + +} diff --git a/src/main/java/cn/nukkit/event/vehicle/VehicleDestroyEvent.java b/src/main/java/cn/nukkit/event/vehicle/VehicleDestroyEvent.java new file mode 100644 index 0000000000..5956c59c19 --- /dev/null +++ b/src/main/java/cn/nukkit/event/vehicle/VehicleDestroyEvent.java @@ -0,0 +1,27 @@ +package cn.nukkit.event.vehicle; + +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.item.EntityVehicle; +import cn.nukkit.event.Cancellable; +import cn.nukkit.event.HandlerList; + +public class VehicleDestroyEvent extends VehicleEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + + public static HandlerList getHandlers() { + return handlers; + } + + private final Entity attacker; + + public VehicleDestroyEvent(EntityVehicle vehicle, Entity attacker) { + super(vehicle); + this.attacker = attacker; + } + + public Entity getAttacker() { + return attacker; + } + +} diff --git a/src/main/java/cn/nukkit/form/element/Element.java b/src/main/java/cn/nukkit/form/element/Element.java new file mode 100644 index 0000000000..fc80c0b7db --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/Element.java @@ -0,0 +1,5 @@ +package cn.nukkit.form.element; + +public abstract class Element { + +} diff --git a/src/main/java/cn/nukkit/form/element/ElementButton.java b/src/main/java/cn/nukkit/form/element/ElementButton.java new file mode 100644 index 0000000000..a95846582f --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementButton.java @@ -0,0 +1,33 @@ +package cn.nukkit.form.element; + +public class ElementButton { + + private String text = ""; + private ElementButtonImageData image; + + public ElementButton(String text) { + this.text = text; + } + + public ElementButton(String text, ElementButtonImageData image) { + this.text = text; + if (!image.getData().isEmpty() && !image.getType().isEmpty()) this.image = image; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public ElementButtonImageData getImage() { + return image; + } + + public void addImage(ElementButtonImageData image) { + if (!image.getData().isEmpty() && !image.getType().isEmpty()) this.image = image; + } + +} diff --git a/src/main/java/cn/nukkit/form/element/ElementButtonImageData.java b/src/main/java/cn/nukkit/form/element/ElementButtonImageData.java new file mode 100644 index 0000000000..e3d0fa4e42 --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementButtonImageData.java @@ -0,0 +1,32 @@ +package cn.nukkit.form.element; + +public class ElementButtonImageData { + + public static final String IMAGE_DATA_TYPE_PATH = "path"; + public static final String IMAGE_DATA_TYPE_URL = "url"; + + private String type; + private String data; + + public ElementButtonImageData(String type, String data) { + if (!type.equals(IMAGE_DATA_TYPE_URL) && !type.equals(IMAGE_DATA_TYPE_PATH)) return; + this.type = type; + this.data = data; + } + + public String getType() { + return type; + } + + public String getData() { + return data; + } + + public void setType(String type) { + this.type = type; + } + + public void setData(String data) { + this.data = data; + } +} diff --git a/src/main/java/cn/nukkit/form/element/ElementDropdown.java b/src/main/java/cn/nukkit/form/element/ElementDropdown.java new file mode 100644 index 0000000000..b10699759b --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementDropdown.java @@ -0,0 +1,57 @@ +package cn.nukkit.form.element; + +import java.util.ArrayList; +import java.util.List; + +public class ElementDropdown extends Element { + + private final String type = "dropdown"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String text = ""; + private List options; + private int defaultOptionIndex = 0; + + public ElementDropdown(String text) { + this(text, new ArrayList<>()); + } + + public ElementDropdown(String text, List options) { + this(text, options, 0); + } + + public ElementDropdown(String text, List options, int defaultOption) { + this.text = text; + this.options = options; + this.defaultOptionIndex = defaultOption; + } + + public int getDefaultOptionIndex() { + return defaultOptionIndex; + } + + public void setDefaultOptionIndex(int index) { + if (index >= options.size()) return; + this.defaultOptionIndex = index; + } + + public List getOptions() { + return options; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public void addOption(String option) { + addOption(option, false); + } + + public void addOption(String option, boolean isDefault) { + options.add(option); + if (isDefault) this.defaultOptionIndex = options.size() - 1; + } + +} diff --git a/src/main/java/cn/nukkit/form/element/ElementInput.java b/src/main/java/cn/nukkit/form/element/ElementInput.java new file mode 100644 index 0000000000..e9af69b817 --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementInput.java @@ -0,0 +1,47 @@ +package cn.nukkit.form.element; + +public class ElementInput extends Element { + + private final String type = "input"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String text = ""; + private String placeholder = ""; + private String defaultText = ""; + + public ElementInput(String text) { + this(text, ""); + } + + public ElementInput(String text, String placeholder) { + this(text, placeholder, ""); + } + + public ElementInput(String text, String placeholder, String defaultText) { + this.text = text; + this.placeholder = placeholder; + this.defaultText = defaultText; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getPlaceHolder() { + return placeholder; + } + + public void setPlaceHolder(String placeholder) { + this.placeholder = placeholder; + } + + public String getDefaultText() { + return defaultText; + } + + public void setDefaultText(String defaultText) { + this.defaultText = defaultText; + } +} diff --git a/src/main/java/cn/nukkit/form/element/ElementLabel.java b/src/main/java/cn/nukkit/form/element/ElementLabel.java new file mode 100644 index 0000000000..449eae0561 --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementLabel.java @@ -0,0 +1,19 @@ +package cn.nukkit.form.element; + +public class ElementLabel extends Element { + + private final String type = "label"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String text = ""; + + public ElementLabel(String text) { + this.text = text; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/src/main/java/cn/nukkit/form/element/ElementSlider.java b/src/main/java/cn/nukkit/form/element/ElementSlider.java new file mode 100644 index 0000000000..8ed077bb75 --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementSlider.java @@ -0,0 +1,67 @@ +package cn.nukkit.form.element; + +public class ElementSlider extends Element { + + private final String type = "slider"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String text = ""; + private float min = 0f; + private float max = 100f; + private int step; + private float defaultValue; + + public ElementSlider(String text, float min, float max) { + this(text, min, max, -1); + } + + public ElementSlider(String text, float min, float max, int step) { + this(text, min, max, step, -1); + } + + public ElementSlider(String text, float min, float max, int step, float defaultValue) { + this.text = text; + this.min = min < 0f ? 0f : min; + this.max = max > this.min ? max : this.min; + if (step != -1f && step > 0) this.step = step; + if (defaultValue != -1f) this.defaultValue = defaultValue; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public float getMin() { + return min; + } + + public void setMin(float min) { + this.min = min; + } + + public float getMax() { + return max; + } + + public void setMax(float max) { + this.max = max; + } + + public int getStep() { + return step; + } + + public void setStep(int step) { + this.step = step; + } + + public float getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(float defaultValue) { + this.defaultValue = defaultValue; + } +} diff --git a/src/main/java/cn/nukkit/form/element/ElementStepSlider.java b/src/main/java/cn/nukkit/form/element/ElementStepSlider.java new file mode 100644 index 0000000000..443a98596c --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementStepSlider.java @@ -0,0 +1,57 @@ +package cn.nukkit.form.element; + +import java.util.ArrayList; +import java.util.List; + +public class ElementStepSlider extends Element { + + private final String type = "step_slider"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String text = ""; + private List steps; + private int defaultStepIndex = 0; + + public ElementStepSlider(String text) { + this(text, new ArrayList<>()); + } + + public ElementStepSlider(String text, List steps) { + this(text, steps, 0); + } + + public ElementStepSlider(String text, List steps, int defaultStep) { + this.text = text; + this.steps = steps; + this.defaultStepIndex = defaultStep; + } + + public int getDefaultStepIndex() { + return defaultStepIndex; + } + + public void setDefaultOptionIndex(int index) { + if (index >= steps.size()) return; + this.defaultStepIndex = index; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public List getSteps() { + return steps; + } + + public void addStep(String step) { + addStep(step, false); + } + + public void addStep(String step, boolean isDefault) { + steps.add(step); + if (isDefault) this.defaultStepIndex = steps.size() - 1; + } + +} diff --git a/src/main/java/cn/nukkit/form/element/ElementToggle.java b/src/main/java/cn/nukkit/form/element/ElementToggle.java new file mode 100644 index 0000000000..2da9d7fdf1 --- /dev/null +++ b/src/main/java/cn/nukkit/form/element/ElementToggle.java @@ -0,0 +1,33 @@ +package cn.nukkit.form.element; + +public class ElementToggle extends Element { + + private final String type = "toggle"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String text = ""; + private boolean defaultValue = false; + + public ElementToggle(String text) { + this(text, false); + } + + public ElementToggle(String text, boolean defaultValue) { + this.text = text; + this.defaultValue = defaultValue; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public boolean isDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(boolean defaultValue) { + this.defaultValue = defaultValue; + } +} diff --git a/src/main/java/cn/nukkit/form/response/FormResponse.java b/src/main/java/cn/nukkit/form/response/FormResponse.java new file mode 100644 index 0000000000..1d128d60f4 --- /dev/null +++ b/src/main/java/cn/nukkit/form/response/FormResponse.java @@ -0,0 +1,5 @@ +package cn.nukkit.form.response; + +public abstract class FormResponse { + +} diff --git a/src/main/java/cn/nukkit/form/response/FormResponseCustom.java b/src/main/java/cn/nukkit/form/response/FormResponseCustom.java new file mode 100644 index 0000000000..b7d3704c88 --- /dev/null +++ b/src/main/java/cn/nukkit/form/response/FormResponseCustom.java @@ -0,0 +1,54 @@ +package cn.nukkit.form.response; + +import java.util.HashMap; + +public class FormResponseCustom extends FormResponse { + + private HashMap responses = new HashMap<>(); + private HashMap dropdownResponses = new HashMap<>(); + private HashMap inputResponses = new HashMap<>(); + private HashMap sliderResponses = new HashMap<>(); + private HashMap stepSliderResponses = new HashMap<>(); + private HashMap toggleResponses = new HashMap<>(); + + public FormResponseCustom(HashMap responses, HashMap dropdownResponses, + HashMap inputResponses, HashMap sliderResponses, + HashMap stepSliderResponses, + HashMap toggleResponses) { + this.responses = responses; + this.dropdownResponses = dropdownResponses; + this.inputResponses = inputResponses; + this.sliderResponses = sliderResponses; + this.stepSliderResponses = stepSliderResponses; + this.toggleResponses = toggleResponses; + } + + public HashMap getResponses() { + return responses; + } + + public Object getResponse(int id) { + return responses.get(id); + } + + public FormResponseData getDropdownResponse(int id) { + return dropdownResponses.get(id); + } + + public String getInputResponse(int id) { + return inputResponses.get(id); + } + + public float getSliderResponse(int id) { + return sliderResponses.get(id); + } + + public FormResponseData getStepSliderResponse(int id) { + return stepSliderResponses.get(id); + } + + public boolean getToggleResponse(int id) { + return toggleResponses.get(id); + } + +} diff --git a/src/main/java/cn/nukkit/form/response/FormResponseData.java b/src/main/java/cn/nukkit/form/response/FormResponseData.java new file mode 100644 index 0000000000..81a3444d44 --- /dev/null +++ b/src/main/java/cn/nukkit/form/response/FormResponseData.java @@ -0,0 +1,21 @@ +package cn.nukkit.form.response; + +public class FormResponseData { + + private int elementID; + private String elementContent; + + public FormResponseData(int id, String content) { + this.elementID = id; + this.elementContent = content; + } + + public int getElementID() { + return elementID; + } + + public String getElementContent() { + return elementContent; + } + +} diff --git a/src/main/java/cn/nukkit/form/response/FormResponseModal.java b/src/main/java/cn/nukkit/form/response/FormResponseModal.java new file mode 100644 index 0000000000..17b6232722 --- /dev/null +++ b/src/main/java/cn/nukkit/form/response/FormResponseModal.java @@ -0,0 +1,21 @@ +package cn.nukkit.form.response; + +public class FormResponseModal extends FormResponse { + + private int clickedButtonId; + private String clickedButtonText; + + public FormResponseModal(int clickedButtonId, String clickedButtonText) { + this.clickedButtonId = clickedButtonId; + this.clickedButtonText = clickedButtonText; + } + + public int getClickedButtonId() { + return clickedButtonId; + } + + public String getClickedButtonText() { + return clickedButtonText; + } + +} diff --git a/src/main/java/cn/nukkit/form/response/FormResponseSimple.java b/src/main/java/cn/nukkit/form/response/FormResponseSimple.java new file mode 100644 index 0000000000..2590942b1f --- /dev/null +++ b/src/main/java/cn/nukkit/form/response/FormResponseSimple.java @@ -0,0 +1,23 @@ +package cn.nukkit.form.response; + +import cn.nukkit.form.element.ElementButton; + +public class FormResponseSimple extends FormResponse { + + private int clickedButtonId; + private ElementButton clickedButton; + + public FormResponseSimple(int clickedButtonId, ElementButton clickedButton) { + this.clickedButtonId = clickedButtonId; + this.clickedButton = clickedButton; + } + + public int getClickedButtonId() { + return clickedButtonId; + } + + public ElementButton getClickedButton() { + return clickedButton; + } + +} diff --git a/src/main/java/cn/nukkit/form/window/FormWindow.java b/src/main/java/cn/nukkit/form/window/FormWindow.java new file mode 100644 index 0000000000..2d4ca78988 --- /dev/null +++ b/src/main/java/cn/nukkit/form/window/FormWindow.java @@ -0,0 +1,19 @@ +package cn.nukkit.form.window; + +import cn.nukkit.form.response.FormResponse; + +public abstract class FormWindow { + + protected boolean closed = false; + + public abstract String getJSONData(); + + public abstract void setResponse(String data); + + public abstract FormResponse getResponse(); + + public boolean wasClosed() { + return closed; + } + +} diff --git a/src/main/java/cn/nukkit/form/window/FormWindowCustom.java b/src/main/java/cn/nukkit/form/window/FormWindowCustom.java new file mode 100644 index 0000000000..4ce0aaf1fe --- /dev/null +++ b/src/main/java/cn/nukkit/form/window/FormWindowCustom.java @@ -0,0 +1,155 @@ +package cn.nukkit.form.window; + +import cn.nukkit.form.element.*; +import cn.nukkit.form.response.FormResponseCustom; +import cn.nukkit.form.response.FormResponseData; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class FormWindowCustom extends FormWindow { + + private final String type = "custom_form"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String title = ""; + private ElementButtonImageData icon; + private List content; + + private FormResponseCustom response; + + public FormWindowCustom(String title) { + this(title, new ArrayList<>()); + } + + public FormWindowCustom(String title, List contents) { + this(title, contents, ""); + } + + public FormWindowCustom(String title, List contents, String icon) { + this.title = title; + this.content = contents; + if (!icon.isEmpty()) this.icon = new ElementButtonImageData(ElementButtonImageData.IMAGE_DATA_TYPE_URL, icon); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public List getElements() { + return content; + } + + public void addElement(Element element) { + content.add(element); + } + + public ElementButtonImageData getIcon() { + return icon; + } + + public void setIcon(String icon) { + if (!icon.isEmpty()) this.icon = new ElementButtonImageData(ElementButtonImageData.IMAGE_DATA_TYPE_URL, icon); + } + + public String getJSONData() { + String toModify = new Gson().toJson(this); + //We need to replace this due to Java not supporting declaring class field 'default' + return toModify.replace("defaultOptionIndex", "default") + .replace("defaultText", "default") + .replace("defaultValue", "default") + .replace("defaultStepIndex", "default"); + } + + public FormResponseCustom getResponse() { + return response; + } + + public void setResponse(String data) { + if (data.equals("null")) { + this.closed = true; + return; + } + + List elementResponses = new Gson().fromJson(data, new TypeToken>() { + }.getType()); + //elementResponses.remove(elementResponses.size() - 1); //submit button //maybe mojang removed that? + + int i = 0; + + HashMap dropdownResponses = new HashMap<>(); + HashMap inputResponses = new HashMap<>(); + HashMap sliderResponses = new HashMap<>(); + HashMap stepSliderResponses = new HashMap<>(); + HashMap toggleResponses = new HashMap<>(); + HashMap responses = new HashMap<>(); + + for (String elementData : elementResponses) { + if (i >= content.size()) { + break; + } + + Element e = content.get(i); + if (e == null) break; + if (e instanceof ElementLabel) { + i++; + continue; + } + if (e instanceof ElementDropdown) { + String answer = ((ElementDropdown) e).getOptions().get(Integer.parseInt(elementData)); + dropdownResponses.put(i, new FormResponseData(Integer.parseInt(elementData), answer)); + responses.put(i, answer); + } else if (e instanceof ElementInput) { + inputResponses.put(i, elementData); + responses.put(i, elementData); + } else if (e instanceof ElementSlider) { + Float answer = Float.parseFloat(elementData); + sliderResponses.put(i, answer); + responses.put(i, answer); + } else if (e instanceof ElementStepSlider) { + String answer = ((ElementStepSlider) e).getSteps().get(Integer.parseInt(elementData)); + stepSliderResponses.put(i, new FormResponseData(Integer.parseInt(elementData), answer)); + responses.put(i, answer); + } else if (e instanceof ElementToggle) { + Boolean answer = Boolean.parseBoolean(elementData); + toggleResponses.put(i, answer); + responses.put(i, answer); + } + i++; + } + + this.response = new FormResponseCustom(responses, dropdownResponses, inputResponses, + sliderResponses, stepSliderResponses, toggleResponses); + } + + /** + * Set Elements from Response + * Used on ServerSettings Form Response. After players set settings, we need to sync these settings to the server. + */ + public void setElementsFromResponse() { + if (this.response != null) { + this.response.getResponses().forEach((i, response) -> { + Element e = content.get(i); + if (e != null) { + if (e instanceof ElementDropdown) { + ((ElementDropdown) e).setDefaultOptionIndex(((ElementDropdown) e).getOptions().indexOf(response)); + } else if (e instanceof ElementInput) { + ((ElementInput) e).setDefaultText((String)response); + } else if (e instanceof ElementSlider) { + ((ElementSlider) e).setDefaultValue((Float)response); + } else if (e instanceof ElementStepSlider) { + ((ElementStepSlider) e).setDefaultOptionIndex(((ElementStepSlider) e).getSteps().indexOf(response)); + } else if (e instanceof ElementToggle) { + ((ElementToggle) e).setDefaultValue((Boolean)response); + } + } + }); + } + } + +} diff --git a/src/main/java/cn/nukkit/form/window/FormWindowModal.java b/src/main/java/cn/nukkit/form/window/FormWindowModal.java new file mode 100644 index 0000000000..f0139942b0 --- /dev/null +++ b/src/main/java/cn/nukkit/form/window/FormWindowModal.java @@ -0,0 +1,72 @@ +package cn.nukkit.form.window; + +import cn.nukkit.form.response.FormResponseModal; +import com.google.gson.Gson; + +public class FormWindowModal extends FormWindow { + + private final String type = "modal"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String title = ""; + private String content = ""; + private String button1 = ""; + private String button2 = ""; + + private FormResponseModal response = null; + + public FormWindowModal(String title, String content, String trueButonText, String falseButtonText) { + this.title = title; + this.content = content; + this.button1 = trueButonText; + this.button2 = falseButtonText; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getButton1() { + return button1; + } + + public void setButton1(String button1) { + this.button1 = button1; + } + + public String getButton2() { + return button2; + } + + public void setButton2(String button2) { + this.button2 = button2; + } + + public String getJSONData() { + return new Gson().toJson(this); + } + + public FormResponseModal getResponse() { + return response; + } + + public void setResponse(String data) { + if (data.equals("null")) { + closed = true; + return; + } + if (data.equals("true")) response = new FormResponseModal(0, button1); + else response = new FormResponseModal(1, button2); + } + +} diff --git a/src/main/java/cn/nukkit/form/window/FormWindowSimple.java b/src/main/java/cn/nukkit/form/window/FormWindowSimple.java new file mode 100644 index 0000000000..3df90500c6 --- /dev/null +++ b/src/main/java/cn/nukkit/form/window/FormWindowSimple.java @@ -0,0 +1,79 @@ +package cn.nukkit.form.window; + +import cn.nukkit.form.element.ElementButton; +import cn.nukkit.form.response.FormResponseSimple; +import com.google.gson.Gson; + +import java.util.ArrayList; +import java.util.List; + +public class FormWindowSimple extends FormWindow { + + private final String type = "form"; //This variable is used for JSON import operations. Do NOT delete :) -- @Snake1999 + private String title = ""; + private String content = ""; + private List buttons; + + private FormResponseSimple response = null; + + public FormWindowSimple(String title, String content) { + this(title, content, new ArrayList<>()); + } + + public FormWindowSimple(String title, String content, List buttons) { + this.title = title; + this.content = content; + this.buttons = buttons; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public List getButtons() { + return buttons; + } + + public void addButton(ElementButton button) { + this.buttons.add(button); + } + + public String getJSONData() { + return new Gson().toJson(this); + } + + public FormResponseSimple getResponse() { + return response; + } + + public void setResponse(String data) { + if (data.equals("null")) { + this.closed = true; + return; + } + int buttonID; + try { + buttonID = Integer.parseInt(data); + } catch (Exception e) { + return; + } + if (buttonID >= this.buttons.size()) { + this.response = new FormResponseSimple(buttonID, null); + return; + } + this.response = new FormResponseSimple(buttonID, buttons.get(buttonID)); + } + +} diff --git a/src/main/java/cn/nukkit/inventory/AnvilInventory.java b/src/main/java/cn/nukkit/inventory/AnvilInventory.java index 05340c1303..b246c49593 100644 --- a/src/main/java/cn/nukkit/inventory/AnvilInventory.java +++ b/src/main/java/cn/nukkit/inventory/AnvilInventory.java @@ -33,12 +33,12 @@ public boolean onRename(Player player, Item resultItem) { Item local = getItem(TARGET); Item second = getItem(SACRIFICE); - if (!resultItem.deepEquals(local, true, false) || resultItem.getCount() != local.getCount()) { + if (!resultItem.equals(local, true, false) || resultItem.getCount() != local.getCount()) { //Item does not match target item. Everything must match except the tags. return false; } - if (local.deepEquals(resultItem)) { + if (local.equals(resultItem)) { //just item transaction return true; } @@ -130,6 +130,7 @@ public boolean onRename(Player player, Item resultItem) { public void onClose(Player who) { super.onClose(who); who.craftingType = Player.CRAFTING_SMALL; + who.resetCraftingGridType(); for (int i = 0; i < 2; ++i) { this.getHolder().getLevel().dropItem(this.getHolder().add(0.5, 0.5, 0.5), this.getItem(i)); @@ -142,4 +143,19 @@ public void onOpen(Player who) { super.onOpen(who); who.craftingType = Player.CRAFTING_ANVIL; } + + /*@Override + public boolean setItem(int index, Item item, boolean send) { + return super.setItem(index, item, false); + } + + @Override + public void sendSlot(int index, Player... players) { + + } + + @Override + public void sendContents(Player... player) { + + }*/ } \ No newline at end of file diff --git a/src/main/java/cn/nukkit/inventory/BaseInventory.java b/src/main/java/cn/nukkit/inventory/BaseInventory.java index 52f927f644..dbbf73ac10 100644 --- a/src/main/java/cn/nukkit/inventory/BaseInventory.java +++ b/src/main/java/cn/nukkit/inventory/BaseInventory.java @@ -8,8 +8,8 @@ import cn.nukkit.event.inventory.InventoryOpenEvent; import cn.nukkit.item.Item; import cn.nukkit.item.ItemBlock; -import cn.nukkit.network.protocol.ContainerSetContentPacket; -import cn.nukkit.network.protocol.ContainerSetSlotPacket; +import cn.nukkit.network.protocol.InventoryContentPacket; +import cn.nukkit.network.protocol.InventorySlotPacket; import java.util.*; @@ -139,7 +139,7 @@ public void setContents(Map items) { } @Override - public boolean setItem(int index, Item item) { + public boolean setItem(int index, Item item, boolean send) { item = item.clone(); if (index < 0 || index >= this.size) { return false; @@ -161,7 +161,7 @@ public boolean setItem(int index, Item item) { Item old = this.getItem(index); this.slots.put(index, item.clone()); - this.onSlotChange(index, old); + this.onSlotChange(index, old, send); return true; } @@ -209,12 +209,12 @@ public void remove(Item item) { } @Override - public int first(Item item) { + public int first(Item item, boolean exact) { int count = Math.max(1, item.getCount()); boolean checkDamage = item.hasMeta(); boolean checkTag = item.getCompoundTag() != null; for (Map.Entry entry : this.getContents().entrySet()) { - if (item.equals(entry.getValue(), checkDamage, checkTag) && entry.getValue().getCount() >= count) { + if (item.equals(entry.getValue(), checkDamage, checkTag) && (entry.getValue().getCount() == count || (!exact && entry.getValue().getCount() > count))) { return entry.getKey(); } } @@ -350,7 +350,7 @@ public Item[] removeItem(Item... slots) { } @Override - public boolean clear(int index) { + public boolean clear(int index, boolean send) { if (this.slots.containsKey(index)) { Item item = new ItemBlock(new BlockAir(), null, 0); Item old = this.slots.get(index); @@ -371,7 +371,7 @@ public boolean clear(int index) { this.slots.remove(index); } - this.onSlotChange(index, old); + this.onSlotChange(index, old, send); } return true; @@ -427,8 +427,10 @@ public void onClose(Player who) { } @Override - public void onSlotChange(int index, Item before) { - this.sendSlot(index, this.getViewers()); + public void onSlotChange(int index, Item before, boolean send) { + if (send) { + this.sendSlot(index, this.getViewers()); + } } @Override @@ -437,21 +439,20 @@ public void sendContents(Player player) { } @Override - public void sendContents(Player[] players) { - ContainerSetContentPacket pk = new ContainerSetContentPacket(); + public void sendContents(Player... players) { + InventoryContentPacket pk = new InventoryContentPacket(); pk.slots = new Item[this.getSize()]; for (int i = 0; i < this.getSize(); ++i) { pk.slots[i] = this.getItem(i); } for (Player player : players) { - pk.eid = player.getId(); int id = player.getWindowId(this); if (id == -1 || !player.spawned) { this.close(player); continue; } - pk.windowid = (byte) id; + pk.inventoryId = id; player.dataPacket(pk); } } @@ -515,8 +516,8 @@ public void sendSlot(int index, Player player) { } @Override - public void sendSlot(int index, Player[] players) { - ContainerSetSlotPacket pk = new ContainerSetSlotPacket(); + public void sendSlot(int index, Player... players) { + InventorySlotPacket pk = new InventorySlotPacket(); pk.slot = index; pk.item = this.getItem(index).clone(); @@ -526,7 +527,7 @@ public void sendSlot(int index, Player[] players) { this.close(player); continue; } - pk.windowid = (byte) id; + pk.inventoryId = id; player.dataPacket(pk); } } diff --git a/src/main/java/cn/nukkit/inventory/BaseTransaction.java b/src/main/java/cn/nukkit/inventory/BaseTransaction.java deleted file mode 100644 index 855a920e0d..0000000000 --- a/src/main/java/cn/nukkit/inventory/BaseTransaction.java +++ /dev/null @@ -1,53 +0,0 @@ -package cn.nukkit.inventory; - -import cn.nukkit.item.Item; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public class BaseTransaction implements Transaction { - - protected final Inventory inventory; - - protected final int slot; - - protected final Item sourceItem; - - protected final Item targetItem; - - protected final long creationTime; - - public BaseTransaction(Inventory inventory, int slot, Item sourceItem, Item targetItem) { - this.inventory = inventory; - this.slot = slot; - this.sourceItem = sourceItem.clone(); - this.targetItem = targetItem.clone(); - this.creationTime = System.currentTimeMillis(); - } - - @Override - public long getCreationTime() { - return creationTime; - } - - @Override - public Inventory getInventory() { - return inventory; - } - - @Override - public int getSlot() { - return slot; - } - - @Override - public Item getSourceItem() { - return sourceItem.clone(); - } - - @Override - public Item getTargetItem() { - return targetItem.clone(); - } -} diff --git a/src/main/java/cn/nukkit/inventory/BigCraftingGrid.java b/src/main/java/cn/nukkit/inventory/BigCraftingGrid.java new file mode 100644 index 0000000000..c4aebc8bc1 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/BigCraftingGrid.java @@ -0,0 +1,16 @@ +package cn.nukkit.inventory; + +/** + * @author CreeperFace + */ +public class BigCraftingGrid extends CraftingGrid { + + public BigCraftingGrid(InventoryHolder holder) { + super(holder, 9); + } + + @Override + public int getSize() { + return 9; + } +} diff --git a/src/main/java/cn/nukkit/inventory/BrewingInventory.java b/src/main/java/cn/nukkit/inventory/BrewingInventory.java index e488581656..dd276f878a 100644 --- a/src/main/java/cn/nukkit/inventory/BrewingInventory.java +++ b/src/main/java/cn/nukkit/inventory/BrewingInventory.java @@ -22,9 +22,21 @@ public void setIngredient(Item item) { setItem(0, item); } + public void setFuel(Item fuel) { + setItem(4, fuel); + } + + public Item getFuel() { + return getItem(4); + } + @Override - public void onSlotChange(int index, Item before) { - super.onSlotChange(index, before); + public void onSlotChange(int index, Item before, boolean send) { + super.onSlotChange(index, before, send); + + if (index >= 0 && index <= 2) { + this.getHolder().updateBlock(); + } this.getHolder().scheduleUpdate(); } diff --git a/src/main/java/cn/nukkit/inventory/ChestInventory.java b/src/main/java/cn/nukkit/inventory/ChestInventory.java index 3d8ac1560d..0faf34ba36 100644 --- a/src/main/java/cn/nukkit/inventory/ChestInventory.java +++ b/src/main/java/cn/nukkit/inventory/ChestInventory.java @@ -4,6 +4,7 @@ import cn.nukkit.blockentity.BlockEntityChest; import cn.nukkit.level.Level; import cn.nukkit.network.protocol.BlockEventPacket; +import cn.nukkit.network.protocol.LevelSoundEventPacket; /** * author: MagicDroidX @@ -34,6 +35,7 @@ public void onOpen(Player who) { Level level = this.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_OPEN, 1, -1, this.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.getHolder().getX() >> 4, (int) this.getHolder().getZ() >> 4, pk); } } @@ -51,6 +53,7 @@ public void onClose(Player who) { Level level = this.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_CLOSED, 1, -1, this.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.getHolder().getX() >> 4, (int) this.getHolder().getZ() >> 4, pk); } } diff --git a/src/main/java/cn/nukkit/inventory/ContainerInventory.java b/src/main/java/cn/nukkit/inventory/ContainerInventory.java index 519db2b712..6238f2d7cd 100644 --- a/src/main/java/cn/nukkit/inventory/ContainerInventory.java +++ b/src/main/java/cn/nukkit/inventory/ContainerInventory.java @@ -34,8 +34,8 @@ public ContainerInventory(InventoryHolder holder, InventoryType type, Map(), overrideSize); + } + + @Override + public int getSize() { + return 4; + } + + public void setSize(int size) { + throw new RuntimeException("Cannot change the size of a crafting grid"); + } + + public String getName() { + return "Crafting"; + } + + public void removeFromAll(Item item) { + int count = item.getCount(); + + for (int i = 0; i < this.size; i++) { + Item target = this.getItem(i); + + if (target.equals(item, true, false)) { + count--; + target.count--; + this.setItem(i, target); + if (count <= 0) break; + } + } + + if (count != 0) { + MainLogger.getLogger().debug("Unexpected ingredient count (" + count + ") in crafting grid"); + } + } + + public void sendSlot(int index, Player... target) { + //we can't send a inventorySlot of a client-sided inventory window + } + + public void sendContents(Player... target) { + //we can't send the contents of a client-sided inventory window + } +} diff --git a/src/main/java/cn/nukkit/inventory/CraftingInventory.java b/src/main/java/cn/nukkit/inventory/CraftingInventory.java deleted file mode 100644 index 005903c6a3..0000000000 --- a/src/main/java/cn/nukkit/inventory/CraftingInventory.java +++ /dev/null @@ -1,27 +0,0 @@ -package cn.nukkit.inventory; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public class CraftingInventory extends BaseInventory { - - private Inventory resultInventory; - - public CraftingInventory(InventoryHolder holder, Inventory resultInventory, InventoryType type) { - super(holder, type); - if (!type.getDefaultTitle().equals("Crafting")) { - throw new IllegalStateException("Invalid Inventory type, expected CRAFTING or WORKBENCH"); - } - this.resultInventory = resultInventory; - } - - public Inventory getResultInventory() { - return resultInventory; - } - - @Override - public int getSize() { - return this.getResultInventory().getSize() + super.getSize(); - } -} diff --git a/src/main/java/cn/nukkit/inventory/CraftingManager.java b/src/main/java/cn/nukkit/inventory/CraftingManager.java index e5a6e1a7c2..41a7e21497 100644 --- a/src/main/java/cn/nukkit/inventory/CraftingManager.java +++ b/src/main/java/cn/nukkit/inventory/CraftingManager.java @@ -10,6 +10,7 @@ import cn.nukkit.utils.MainLogger; import cn.nukkit.utils.Utils; +import java.io.File; import java.io.IOException; import java.util.*; @@ -32,13 +33,17 @@ public class CraftingManager { public static CraftingDataPacket packet = null; public CraftingManager() { - try { - Utils.writeFile(Server.getInstance().getDataPath() + "recipes.json", Server.class.getClassLoader().getResourceAsStream("recipes.json")); - } catch (IOException e) { - MainLogger.getLogger().logException(e); - //return; + String path = Server.getInstance().getDataPath() + "recipes.json"; + + if (!new File(path).exists()) { + try { + Utils.writeFile(path, Server.class.getClassLoader().getResourceAsStream("recipes.json")); + } catch (IOException e) { + MainLogger.getLogger().logException(e); + } } - List recipes = new Config(Server.getInstance().getDataPath() + "recipes.json", Config.JSON).getMapList("recipes"); + + List recipes = new Config(path, Config.JSON).getMapList("recipes"); MainLogger.getLogger().info("Loading recipes..."); for (Map recipe : recipes) { //TODO: implement this better switch (Utils.toInt(recipe.get("type"))) { @@ -47,9 +52,15 @@ public CraftingManager() { Map first = ((List) recipe.get("output")).get(0); ShapelessRecipe result = new ShapelessRecipe(Item.get(Utils.toInt(first.get("id")), Utils.toInt(first.get("damage")), Utils.toInt(first.get("count")), first.get("nbt").toString().getBytes())); for (Map ingredient : ((List) recipe.get("input"))) { - result.addIngredient(Item.get(Utils.toInt(ingredient.get("id")), Utils.toInt(ingredient.get("damage")), /*Utils.toInt(ingredient.get("count"))*/ 1, ingredient.get("nbt").toString().getBytes())); //ingredient count should be always 1 for now + result.addIngredient(Item.get(Utils.toInt(ingredient.get("id")), Utils.toInt(ingredient.get("damage")), Utils.toInt(ingredient.get("count")), ingredient.get("nbt").toString().getBytes())); + } + + String id = (String) recipe.get("uuid"); + if (id != null && !id.isEmpty()) { + UUID uuid = UUID.fromString(id); + result.setId(uuid); + this.registerShapelessRecipe(result); } - this.registerRecipe(result); break; case 1: // TODO: handle multiple result items @@ -63,19 +74,26 @@ public CraftingManager() { if (data instanceof Map) { Map ingredient = (Map) data; - shapedRecipe.addIngredient(x, y, Item.get(Utils.toInt(ingredient.get("id")), Utils.toInt(ingredient.get("damage")), /*Utils.toInt(ingredient.get("count"))*/ 1, ingredient.get("nbt").toString().getBytes())); + shapedRecipe.addIngredient(x, y, Item.get(Utils.toInt(ingredient.get("id")), Utils.toInt(ingredient.get("damage")), Utils.toInt(ingredient.get("count")), ingredient.get("nbt").toString().getBytes())); } else { shapedRecipe.addIngredient(x, y, new ItemBlock(new BlockAir())); } } } - this.registerRecipe(shapedRecipe); + + id = (String) recipe.get("uuid"); + + if (id != null && !id.isEmpty()) { + UUID uuid = UUID.fromString(id); + shapedRecipe.setId(uuid); + this.registerShapedRecipe(shapedRecipe); + } break; case 2: case 3: Map resultMap = (Map) recipe.get("output"); Item resultItem = Item.get(Utils.toInt(resultMap.get("id")), Utils.toInt(resultMap.get("damage")), Utils.toInt(resultMap.get("count")), ((String) resultMap.get("nbt")).getBytes()); - this.registerRecipe(new FurnaceRecipe(resultItem, Item.get(Utils.toInt(recipe.get("inputId")), recipe.containsKey("inputDamage") ? Utils.toInt(recipe.get("inputDamage")) : -1, 1))); + this.registerRecipe(new FurnaceRecipe(resultItem, Item.get(Utils.toInt(recipe.get("inputId")), recipe.containsKey("inputDamage") ? Utils.toInt(recipe.get("inputDamage")) : 0, 1))); break; default: break; @@ -302,7 +320,7 @@ public boolean matchRecipe(ShapelessRecipe recipe) { } public void registerRecipe(Recipe recipe) { - recipe.setId(Utils.dataToUUID(String.valueOf(++RECIPE_COUNT), String.valueOf(recipe.getResult().getId()), String.valueOf(recipe.getResult().getDamage()), String.valueOf(recipe.getResult().getCount()), Arrays.toString(recipe.getResult().getCompoundTag()))); + //recipe.setId(Utils.dataToUUID(String.valueOf(++RECIPE_COUNT), String.valueOf(recipe.getResult().getId()), String.valueOf(recipe.getResult().getDamage()), String.valueOf(recipe.getResult().getCount()), Arrays.toString(recipe.getResult().getCompoundTag()))); if (recipe instanceof ShapedRecipe) { this.registerShapedRecipe((ShapedRecipe) recipe); @@ -314,6 +332,8 @@ public void registerRecipe(Recipe recipe) { } public Recipe[] getRecipesByResult(Item result) { + Map lookup = recipeLookup.get(result.getId() + ":" + result.getDamage()); + if (lookup == null) return new Recipe[0]; return recipeLookup.get(result.getId() + ":" + result.getDamage()).values().stream().toArray(Recipe[]::new); } diff --git a/src/main/java/cn/nukkit/inventory/DoubleChestInventory.java b/src/main/java/cn/nukkit/inventory/DoubleChestInventory.java index a2337ead25..522e030bae 100644 --- a/src/main/java/cn/nukkit/inventory/DoubleChestInventory.java +++ b/src/main/java/cn/nukkit/inventory/DoubleChestInventory.java @@ -5,6 +5,7 @@ import cn.nukkit.item.Item; import cn.nukkit.level.Level; import cn.nukkit.network.protocol.BlockEventPacket; +import cn.nukkit.network.protocol.LevelSoundEventPacket; import java.util.HashMap; import java.util.Map; @@ -57,8 +58,8 @@ public Item getItem(int index) { } @Override - public boolean setItem(int index, Item item) { - return index < this.left.getSize() ? this.left.setItem(index, item) : this.right.setItem(index - this.right.getSize(), item); + public boolean setItem(int index, Item item, boolean send) { + return index < this.left.getSize() ? this.left.setItem(index, item, send) : this.right.setItem(index - this.right.getSize(), item, send); } @Override @@ -105,6 +106,8 @@ public void setContents(Map items) { @Override public void onOpen(Player who) { super.onOpen(who); + this.left.viewers.add(who); + this.right.viewers.add(who); if (this.getViewers().size() == 1) { BlockEventPacket pk1 = new BlockEventPacket(); @@ -115,6 +118,7 @@ public void onOpen(Player who) { pk1.case2 = 2; Level level = this.left.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_OPEN, 1, -1, this.left.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.left.getHolder().getX() >> 4, (int) this.left.getHolder().getZ() >> 4, pk1); } @@ -127,6 +131,7 @@ public void onOpen(Player who) { level = this.right.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_OPEN, 1, -1, this.right.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.right.getHolder().getX() >> 4, (int) this.right.getHolder().getZ() >> 4, pk2); } } @@ -144,6 +149,7 @@ public void onClose(Player who) { Level level = this.right.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_CLOSED, 1, -1, this.right.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.right.getHolder().getX() >> 4, (int) this.right.getHolder().getZ() >> 4, pk1); } @@ -156,10 +162,13 @@ public void onClose(Player who) { level = this.left.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_CLOSED, 1, -1, this.left.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.left.getHolder().getX() >> 4, (int) this.left.getHolder().getZ() >> 4, pk2); } } + this.left.viewers.remove(who); + this.right.viewers.remove(who); super.onClose(who); } diff --git a/src/main/java/cn/nukkit/inventory/EnchantInventory.java b/src/main/java/cn/nukkit/inventory/EnchantInventory.java index 38476755dc..0f74ff60a5 100644 --- a/src/main/java/cn/nukkit/inventory/EnchantInventory.java +++ b/src/main/java/cn/nukkit/inventory/EnchantInventory.java @@ -1,12 +1,14 @@ package cn.nukkit.inventory; import cn.nukkit.Player; -import cn.nukkit.Server; +import cn.nukkit.block.Block; import cn.nukkit.item.Item; import cn.nukkit.item.ItemBookEnchanted; import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.item.enchantment.EnchantmentEntry; import cn.nukkit.item.enchantment.EnchantmentList; +import cn.nukkit.level.Level; +import cn.nukkit.level.Location; import cn.nukkit.level.Position; import cn.nukkit.math.NukkitRandom; import cn.nukkit.network.protocol.CraftingDataPacket; @@ -67,8 +69,8 @@ public void onOpen(Player who) { } @Override - public void onSlotChange(int index, Item before) { - super.onSlotChange(index, before); + public void onSlotChange(int index, Item before, boolean send) { + super.onSlotChange(index, before, send); if (index == 0) { Item item = this.getItem(0); @@ -218,8 +220,38 @@ public void onEnchant(Player who, Item before, Item after) { } public int countBookshelf() { - return 15; - //todo calculate bookshelf + int count = 0; + Location loc = this.getHolder().getLocation(); + Level level = loc.getLevel(); + + for (int y = 0; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + for (int z = -1; z <= 1; z++) { + if (z == 0 && x == 0) continue; + if (level.getBlock(loc.add(x, 0, z)).isTransparent()) { + if (level.getBlock(loc.add(0, 1, 0)).isTransparent()) { + //diagonal and straight + if (level.getBlock(loc.add(x << 1, y, z << 1)).getId() == Block.BOOKSHELF) { + count++; + } + + if (x != 0 && z != 0) { + //one block diagonal and one straight + if (level.getBlock(loc.add(x << 1, y, z)).getId() == Block.BOOKSHELF) { + ++count; + } + + if (level.getBlock(loc.add(x, y, z << 1)).getId() == Block.BOOKSHELF) { + ++count; + } + } + } + } + } + } + } + + return count; } public void sendEnchantmentList() { @@ -232,7 +264,21 @@ public void sendEnchantmentList() { pk.addEnchantList(list); } - Server.broadcastPacket(this.getViewers(), pk); + //Server.broadcastPacket(this.getViewers(), pk); //TODO: fix this, causes crash in 1.2 + } + + /*@Override + public void sendSlot(int index, Player... players) { + } + @Override + public void sendContents(Player... players) { + + } + + @Override + public boolean setItem(int index, Item item, boolean send) { + return super.setItem(index, item, false); + }*/ } diff --git a/src/main/java/cn/nukkit/inventory/FurnaceInventory.java b/src/main/java/cn/nukkit/inventory/FurnaceInventory.java index ad45f761a0..34cef28646 100644 --- a/src/main/java/cn/nukkit/inventory/FurnaceInventory.java +++ b/src/main/java/cn/nukkit/inventory/FurnaceInventory.java @@ -43,8 +43,8 @@ public boolean setSmelting(Item item) { } @Override - public void onSlotChange(int index, Item before) { - super.onSlotChange(index, before); + public void onSlotChange(int index, Item before, boolean send) { + super.onSlotChange(index, before, send); this.getHolder().scheduleUpdate(); } diff --git a/src/main/java/cn/nukkit/inventory/Inventory.java b/src/main/java/cn/nukkit/inventory/Inventory.java index 8074ffc57a..ba7e4cdf6e 100644 --- a/src/main/java/cn/nukkit/inventory/Inventory.java +++ b/src/main/java/cn/nukkit/inventory/Inventory.java @@ -27,7 +27,11 @@ public interface Inventory { Item getItem(int index); - boolean setItem(int index, Item item); + default boolean setItem(int index, Item item) { + return setItem(index, item, true); + } + + boolean setItem(int index, Item item, boolean send); Item[] addItem(Item... slots); @@ -41,13 +45,13 @@ public interface Inventory { void sendContents(Player player); - void sendContents(Player[] players); + void sendContents(Player... players); void sendContents(Collection players); void sendSlot(int index, Player player); - void sendSlot(int index, Player[] players); + void sendSlot(int index, Player... players); void sendSlot(int index, Collection players); @@ -55,13 +59,21 @@ public interface Inventory { Map all(Item item); - int first(Item item); + default int first(Item item) { + return first(item, false); + } + + int first(Item item, boolean exact); int firstEmpty(Item item); void remove(Item item); - boolean clear(int index); + default boolean clear(int index) { + return clear(index, true); + } + + boolean clear(int index, boolean send); void clearAll(); @@ -83,5 +95,5 @@ public interface Inventory { void onClose(Player who); - void onSlotChange(int index, Item before); + void onSlotChange(int index, Item before, boolean send); } diff --git a/src/main/java/cn/nukkit/inventory/InventoryType.java b/src/main/java/cn/nukkit/inventory/InventoryType.java index bac09d0e96..f6ac77f11c 100644 --- a/src/main/java/cn/nukkit/inventory/InventoryType.java +++ b/src/main/java/cn/nukkit/inventory/InventoryType.java @@ -8,16 +8,17 @@ public enum InventoryType { CHEST(27, "Chest", 0), ENDER_CHEST(27, "Ender Chest", 0), DOUBLE_CHEST(27 + 27, "Double Chest", 0), - PLAYER(40, "Player", 0), //36 CONTAINER, 4 ARMOR + PLAYER(40, "Player", -1), //36 CONTAINER, 4 ARMOR FURNACE(3, "Furnace", 2), CRAFTING(5, "Crafting", 1), //4 CRAFTING slots, 1 RESULT WORKBENCH(10, "Crafting", 1), //9 CRAFTING slots, 1 RESULT - BREWING_STAND(4, "Brewing", 4), //1 INPUT, 3 POTION + BREWING_STAND(5, "Brewing", 4), //1 INPUT, 3 POTION, 1 fuel ANVIL(3, "Anvil", 5), //2 INPUT, 1 OUTPUT ENCHANT_TABLE(2, "Enchant", 3), //1 INPUT/OUTPUT, 1 LAPIS DISPENSER(0, "Dispenser", 6), //9 CONTAINER DROPPER(9, "Dropper", 7), //9 CONTAINER - HOPPER(5, "Hopper", 8); //5 CONTAINER + HOPPER(5, "Hopper", 8), //5 CONTAINER + CURSOR(1, "Cursor", -1); private final int size; private final String title; diff --git a/src/main/java/cn/nukkit/inventory/PlayerCursorInventory.java b/src/main/java/cn/nukkit/inventory/PlayerCursorInventory.java new file mode 100644 index 0000000000..5d94813115 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/PlayerCursorInventory.java @@ -0,0 +1,58 @@ +package cn.nukkit.inventory; + +import cn.nukkit.Player; +import cn.nukkit.network.protocol.InventorySlotPacket; +import cn.nukkit.network.protocol.types.ContainerIds; + +/** + * @author CreeperFace + */ +public class PlayerCursorInventory extends BaseInventory { + + public PlayerCursorInventory(Player holder) { + super(holder, InventoryType.CURSOR); + } + + public String getName() { + return "Cursor"; + } + + public int getSize() { + return 1; + } + + public void setSize(int size) { + throw new RuntimeException("Cursor can only carry one item at a time"); + } + + public void sendSlot(int index, Player... target) { + InventorySlotPacket pk = new InventorySlotPacket(); + pk.slot = index; + pk.item = this.getItem(index); + + for (Player p : target) { + if (p == this.getHolder()) { + pk.inventoryId = ContainerIds.CURSOR; + p.dataPacket(pk); + } else { + int id; + + if ((id = p.getWindowId(this)) == ContainerIds.NONE) { + this.close(p); + continue; + } + pk.inventoryId = id; + p.dataPacket(pk); + } + } + } + + /** + * This override is here for documentation and code completion purposes only. + * + * @return Player + */ + public Player getHolder() { + return (Player) this.holder; + } +} diff --git a/src/main/java/cn/nukkit/inventory/PlayerEnderChestInventory.java b/src/main/java/cn/nukkit/inventory/PlayerEnderChestInventory.java old mode 100644 new mode 100755 index 64472789f1..d72fa0d603 --- a/src/main/java/cn/nukkit/inventory/PlayerEnderChestInventory.java +++ b/src/main/java/cn/nukkit/inventory/PlayerEnderChestInventory.java @@ -8,6 +8,7 @@ import cn.nukkit.network.protocol.BlockEventPacket; import cn.nukkit.network.protocol.ContainerClosePacket; import cn.nukkit.network.protocol.ContainerOpenPacket; +import cn.nukkit.network.protocol.LevelSoundEventPacket; public class PlayerEnderChestInventory extends BaseInventory { @@ -27,8 +28,8 @@ public void onOpen(Player who) { } super.onOpen(who); ContainerOpenPacket containerOpenPacket = new ContainerOpenPacket(); - containerOpenPacket.windowid = (byte) who.getWindowId(this); - containerOpenPacket.type = (byte) this.getType().getNetworkType(); + containerOpenPacket.windowId = who.getWindowId(this); + containerOpenPacket.type = this.getType().getNetworkType(); BlockEnderChest chest = who.getViewingEnderChest(); if (chest != null) { containerOpenPacket.x = (int) chest.getX(); @@ -52,6 +53,7 @@ public void onOpen(Player who) { Level level = this.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_OPEN, 1, -1, this.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.getHolder().getX() >> 4, (int) this.getHolder().getZ() >> 4, blockEventPacket); } } @@ -60,7 +62,7 @@ public void onOpen(Player who) { @Override public void onClose(Player who) { ContainerClosePacket containerClosePacket = new ContainerClosePacket(); - containerClosePacket.windowid = (byte) who.getWindowId(this); + containerClosePacket.windowId = who.getWindowId(this); who.dataPacket(containerClosePacket); super.onClose(who); @@ -75,6 +77,7 @@ public void onClose(Player who) { Level level = this.getHolder().getLevel(); if (level != null) { + level.addLevelSoundEvent(LevelSoundEventPacket.SOUND_CHEST_CLOSED, 1, -1, this.getHolder().add(0.5, 0.5, 0.5)); level.addChunkPacket((int) this.getHolder().getX() >> 4, (int) this.getHolder().getZ() >> 4, blockEventPacket); } diff --git a/src/main/java/cn/nukkit/inventory/PlayerInventory.java b/src/main/java/cn/nukkit/inventory/PlayerInventory.java index a739a82299..dde668532b 100644 --- a/src/main/java/cn/nukkit/inventory/PlayerInventory.java +++ b/src/main/java/cn/nukkit/inventory/PlayerInventory.java @@ -10,10 +10,11 @@ import cn.nukkit.event.player.PlayerItemHeldEvent; import cn.nukkit.item.Item; import cn.nukkit.item.ItemBlock; -import cn.nukkit.network.protocol.ContainerSetContentPacket; -import cn.nukkit.network.protocol.ContainerSetSlotPacket; +import cn.nukkit.network.protocol.InventoryContentPacket; +import cn.nukkit.network.protocol.InventorySlotPacket; import cn.nukkit.network.protocol.MobArmorEquipmentPacket; import cn.nukkit.network.protocol.MobEquipmentPacket; +import cn.nukkit.network.protocol.types.ContainerIds; import java.util.Collection; @@ -24,15 +25,16 @@ public class PlayerInventory extends BaseInventory { protected int itemInHandIndex = 0; - - protected final int[] hotbar; + private int[] hotbar; public PlayerInventory(EntityHumanType player) { super(player, InventoryType.PLAYER); this.hotbar = new int[this.getHotbarSize()]; + for (int i = 0; i < this.hotbar.length; i++) { this.hotbar[i] = i; } + } @Override @@ -46,30 +48,69 @@ public void setSize(int size) { this.sendContents(this.getViewers()); } + /** + * Called when a client equips a hotbar inventorySlot. This method should not be used by plugins. + * This method will call PlayerItemHeldEvent. + * + * @param slot hotbar slot Number of the hotbar slot to equip. + * @return boolean if the equipment change was successful, false if not. + */ + public boolean equipItem(int slot) { + if (!isHotbarSlot(slot)) { + this.sendContents((Player) this.getHolder()); + return false; + } + + if (this.getHolder() instanceof Player) { + PlayerItemHeldEvent ev = new PlayerItemHeldEvent((Player) this.getHolder(), this.getItem(slot), slot); + this.getHolder().getLevel().getServer().getPluginManager().callEvent(ev); + + if (ev.isCancelled()) { + this.sendContents(this.getViewers()); + return false; + } + } + + this.setHeldItemIndex(slot, false); + return true; + } + + private boolean isHotbarSlot(int slot) { + return slot >= 0 && slot <= this.getHotbarSize(); + } + + @Deprecated public int getHotbarSlotIndex(int index) { - return (index >= 0 && index < this.getHotbarSize()) ? this.hotbar[index] : -1; + return index; } + @Deprecated public void setHotbarSlotIndex(int index, int slot) { - if (index >= 0 && index < this.getHotbarSize() && slot >= -1 && slot < this.getSize()) { - this.hotbar[index] = slot; - } + } public int getHeldItemIndex() { - return itemInHandIndex; + return this.itemInHandIndex; } public void setHeldItemIndex(int index) { + setHeldItemIndex(index, true); + } + + public void setHeldItemIndex(int index, boolean send) { if (index >= 0 && index < this.getHotbarSize()) { this.itemInHandIndex = index; + if (this.getHolder() instanceof Player && send) { + this.sendHeldItem((Player) this.getHolder()); + } + this.sendHeldItem(this.getHolder().getViewers().values()); } } public Item getItemInHand() { - Item item = this.getItem(this.getHeldItemSlot()); + Item item = this.getItem(this.getHeldItemIndex()); if (item != null) { return item; } else { @@ -78,60 +119,40 @@ public Item getItemInHand() { } public boolean setItemInHand(Item item) { - return this.setItem(this.getHeldItemSlot(), item); + return this.setItem(this.getHeldItemIndex(), item); } + @Deprecated public int getHeldItemSlot() { - return this.getHotbarSlotIndex(this.itemInHandIndex); + return this.itemInHandIndex; } public void setHeldItemSlot(int slot) { - if (slot >= -1 && slot < this.getSize()) { - Item item = this.getItem(slot); - - int itemIndex = this.getHeldItemIndex(); - - if (this.getHolder() instanceof Player) { - PlayerItemHeldEvent ev = new PlayerItemHeldEvent((Player) this.getHolder(), item, slot, itemIndex); - Server.getInstance().getPluginManager().callEvent(ev); - if (ev.isCancelled()) { - this.sendContents((Player) this.getHolder()); - return; - } - } - - this.setHotbarSlotIndex(itemIndex, slot); + if (!isHotbarSlot(slot)) { + return; } - } - public void sendHeldItem(Player player) { - Item item = this.getItemInHand(); - - MobEquipmentPacket pk = new MobEquipmentPacket(); - pk.eid = this.getHolder().getId(); - pk.item = item; - pk.slot = (byte) this.getHeldItemSlot(); - pk.selectedSlot = (byte) this.getHeldItemIndex(); + this.itemInHandIndex = slot; - player.dataPacket(pk); - if (player.equals(this.getHolder())) { - this.sendSlot(this.getHeldItemSlot(), player); + if (this.getHolder() instanceof Player) { + this.sendHeldItem((Player) this.getHolder()); } + + this.sendHeldItem(this.getViewers()); } - public void sendHeldItem(Player[] players) { + public void sendHeldItem(Player... players) { Item item = this.getItemInHand(); MobEquipmentPacket pk = new MobEquipmentPacket(); pk.item = item; - pk.slot = (byte) this.getHeldItemSlot(); - pk.selectedSlot = (byte) this.getHeldItemIndex(); + pk.inventorySlot = pk.hotbarSlot = this.getHeldItemIndex(); for (Player player : players) { pk.eid = this.getHolder().getId(); if (player.equals(this.getHolder())) { pk.eid = player.getId(); - this.sendSlot(this.getHeldItemSlot(), player); + this.sendSlot(this.getHeldItemIndex(), player); } player.dataPacket(pk); @@ -143,17 +164,17 @@ public void sendHeldItem(Collection players) { } @Override - public void onSlotChange(int index, Item before) { + public void onSlotChange(int index, Item before, boolean send) { EntityHuman holder = this.getHolder(); if (holder instanceof Player && !((Player) holder).spawned) { return; } - super.onSlotChange(index, before); - if (index >= this.getSize()) { this.sendArmorSlot(index, this.getViewers()); this.sendArmorSlot(index, this.getHolder().getViewers().values()); + } else { + super.onSlotChange(index, before, send); } } @@ -207,10 +228,10 @@ public boolean setBoots(Item boots) { @Override public boolean setItem(int index, Item item) { - return setItem(index, item, false); + return setItem(index, item, true, false); } - private boolean setItem(int index, Item item, boolean ignoreArmorEvents) { + private boolean setItem(int index, Item item, boolean send, boolean ignoreArmorEvents) { if (index < 0 || index >= this.size) { return false; } else if (item.getId() == 0 || item.getCount() <= 0) { @@ -235,16 +256,14 @@ private boolean setItem(int index, Item item, boolean ignoreArmorEvents) { } item = ev.getNewItem(); } - Item old = this.getItem(index); this.slots.put(index, item.clone()); - this.onSlotChange(index, old); - + this.onSlotChange(index, old, send); return true; } @Override - public boolean clear(int index) { + public boolean clear(int index, boolean send) { if (this.slots.containsKey(index)) { Item item = new ItemBlock(new BlockAir(), null, 0); Item old = this.slots.get(index); @@ -280,7 +299,7 @@ public boolean clear(int index) { this.slots.remove(index); } - this.onSlotChange(index, old); + this.onSlotChange(index, old, send); } return true; @@ -318,9 +337,8 @@ public void sendArmorContents(Player[] players) { for (Player player : players) { if (player.equals(this.getHolder())) { - ContainerSetContentPacket pk2 = new ContainerSetContentPacket(); - pk2.windowid = ContainerSetContentPacket.SPECIAL_ARMOR; - pk2.eid = player.getId(); + InventoryContentPacket pk2 = new InventoryContentPacket(); + pk2.inventoryId = InventoryContentPacket.SPECIAL_ARMOR; pk2.slots = armor; player.dataPacket(pk2); } else { @@ -368,8 +386,8 @@ public void sendArmorSlot(int index, Player[] players) { for (Player player : players) { if (player.equals(this.getHolder())) { - ContainerSetSlotPacket pk2 = new ContainerSetSlotPacket(); - pk2.windowid = ContainerSetContentPacket.SPECIAL_ARMOR; + InventorySlotPacket pk2 = new InventorySlotPacket(); + pk2.inventoryId = InventoryContentPacket.SPECIAL_ARMOR; pk2.slot = index - this.getSize(); pk2.item = this.getItem(index); player.dataPacket(pk2); @@ -395,33 +413,28 @@ public void sendContents(Collection players) { @Override public void sendContents(Player[] players) { - ContainerSetContentPacket pk = new ContainerSetContentPacket(); - pk.slots = new Item[this.getSize() + + this.getHotbarSize()]; + InventoryContentPacket pk = new InventoryContentPacket(); + pk.slots = new Item[this.getSize()]; for (int i = 0; i < this.getSize(); ++i) { pk.slots[i] = this.getItem(i); } - //Because PE is stupid and shows 9 less slots than you send it, give it 9 dummy slots so it shows all the REAL slots. + /*//Because PE is stupid and shows 9 less slots than you send it, give it 9 dummy slots so it shows all the REAL slots. for(int i = this.getSize(); i < this.getSize() + this.getHotbarSize(); ++i){ pk.slots[i] = new ItemBlock(new BlockAir()); } + pk.slots[i] = new ItemBlock(new BlockAir()); + }*/ for (Player player : players) { - if (player.equals(this.getHolder())) { - pk.hotbar = new int[this.getHotbarSize()]; - for (int i = 0; i < this.getHotbarSize(); ++i) { - int index = this.getHotbarSlotIndex(i); - pk.hotbar[i] = index <= -1 ? -1 : index + 9; - } - } int id = player.getWindowId(this); if (id == -1 || !player.spawned) { this.close(player); continue; } - pk.eid = player.getId(); - pk.windowid = (byte) id; + pk.inventoryId = id; player.dataPacket(pk.clone()); + } } @@ -436,14 +449,14 @@ public void sendSlot(int index, Collection players) { } @Override - public void sendSlot(int index, Player[] players) { - ContainerSetSlotPacket pk = new ContainerSetSlotPacket(); + public void sendSlot(int index, Player... players) { + InventorySlotPacket pk = new InventorySlotPacket(); pk.slot = index; pk.item = this.getItem(index).clone(); for (Player player : players) { if (player.equals(this.getHolder())) { - pk.windowid = 0; + pk.inventoryId = ContainerIds.INVENTORY; player.dataPacket(pk); } else { int id = player.getWindowId(this); @@ -451,12 +464,28 @@ public void sendSlot(int index, Player[] players) { this.close(player); continue; } - pk.windowid = (byte) id; + pk.inventoryId = id; player.dataPacket(pk.clone()); } } } + public void sendCreativeContents() { + if (!(this.getHolder() instanceof Player)) { + return; + } + Player p = (Player) this.getHolder(); + + InventoryContentPacket pk = new InventoryContentPacket(); + pk.inventoryId = ContainerIds.CREATIVE; + + if (!p.isSpectator()) { //fill it for all gamemodes except spectator + pk.slots = Item.getCreativeItems().stream().toArray(Item[]::new); + } + + p.dataPacket(pk); + } + @Override public EntityHuman getHolder() { return (EntityHuman) super.getHolder(); diff --git a/src/main/java/cn/nukkit/inventory/Recipe.java b/src/main/java/cn/nukkit/inventory/Recipe.java index 5fcaa90a11..a5c0a42973 100644 --- a/src/main/java/cn/nukkit/inventory/Recipe.java +++ b/src/main/java/cn/nukkit/inventory/Recipe.java @@ -17,4 +17,8 @@ public interface Recipe { UUID getId(); void setId(UUID id); + + default boolean requiresCraftingTable() { + return false; + } } diff --git a/src/main/java/cn/nukkit/inventory/ShapedRecipe.java b/src/main/java/cn/nukkit/inventory/ShapedRecipe.java index 38b454a227..f479015760 100644 --- a/src/main/java/cn/nukkit/inventory/ShapedRecipe.java +++ b/src/main/java/cn/nukkit/inventory/ShapedRecipe.java @@ -134,6 +134,11 @@ public void registerToCraftingManager() { Server.getInstance().getCraftingManager().registerShapedRecipe(this); } + @Override + public boolean requiresCraftingTable() { + return this.getHeight() > 2 || this.getWidth() > 2; + } + public static class Entry { public final int x; public final int y; diff --git a/src/main/java/cn/nukkit/inventory/ShapelessRecipe.java b/src/main/java/cn/nukkit/inventory/ShapelessRecipe.java index cb813a04aa..8892a80ecd 100644 --- a/src/main/java/cn/nukkit/inventory/ShapelessRecipe.java +++ b/src/main/java/cn/nukkit/inventory/ShapelessRecipe.java @@ -94,4 +94,9 @@ public int getIngredientCount() { public void registerToCraftingManager() { Server.getInstance().getCraftingManager().registerShapelessRecipe(this); } + + @Override + public boolean requiresCraftingTable() { + return this.ingredients.size() > 4; + } } diff --git a/src/main/java/cn/nukkit/inventory/SimpleTransactionGroup.java b/src/main/java/cn/nukkit/inventory/SimpleTransactionGroup.java deleted file mode 100644 index fb3f78100b..0000000000 --- a/src/main/java/cn/nukkit/inventory/SimpleTransactionGroup.java +++ /dev/null @@ -1,155 +0,0 @@ -package cn.nukkit.inventory; - -import cn.nukkit.Player; -import cn.nukkit.Server; -import cn.nukkit.event.inventory.InventoryTransactionEvent; -import cn.nukkit.item.Item; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public class SimpleTransactionGroup implements TransactionGroup { - - private final long creationTime; - protected boolean hasExecuted = false; - - protected Player source = null; - - protected final Set inventories = new HashSet<>(); - - protected final Set transactions = new HashSet<>(); - - public SimpleTransactionGroup() { - this(null); - } - - public SimpleTransactionGroup(Player source) { - this.creationTime = System.currentTimeMillis(); - this.source = source; - } - - public Player getSource() { - return source; - } - - @Override - public long getCreationTime() { - return creationTime; - } - - @Override - public Set getInventories() { - return inventories; - } - - @Override - public Set getTransactions() { - return transactions; - } - - @Override - public void addTransaction(Transaction transaction) { - if (this.transactions.contains(transaction)) { - return; - } - - for (Transaction tx : new HashSet<>(this.transactions)) { - if (tx.getInventory().equals(transaction.getInventory()) && tx.getSlot() == transaction.getSlot()) { - if (transaction.getCreationTime() >= tx.getCreationTime()) { - this.transactions.remove(tx); - } else { - return; - } - } - } - - this.transactions.add(transaction); - this.inventories.add(transaction.getInventory()); - } - - protected boolean matchItems(List needItems, List haveItems) { - for (Transaction ts : this.transactions) { - if (ts.getTargetItem().getId() != Item.AIR) { - needItems.add(ts.getTargetItem()); - } - Item checkSourceItem = ts.getInventory().getItem(ts.getSlot()); - Item sourceItem = ts.getSourceItem(); - if (!checkSourceItem.deepEquals(sourceItem) || sourceItem.getCount() != checkSourceItem.getCount()) { - return false; - } - if (sourceItem.getId() != Item.AIR) { - haveItems.add(sourceItem); - } - } - - for (Item needItem : new ArrayList<>(needItems)) { - for (Item haveItem : new ArrayList<>(haveItems)) { - if (needItem.deepEquals(haveItem)) { - int amount = Math.min(haveItem.getCount(), needItem.getCount()); - needItem.setCount(needItem.getCount() - amount); - haveItem.setCount(haveItem.getCount() - amount); - if (haveItem.getCount() == 0) { - haveItems.remove(haveItem); - } - if (needItem.getCount() == 0) { - needItems.remove(needItem); - break; - } - } - } - } - - return true; - } - - @Override - public boolean canExecute() { - List haveItems = new ArrayList<>(); - List needItems = new ArrayList<>(); - - return this.matchItems(needItems, haveItems) && haveItems.isEmpty() && needItems.isEmpty() && !this.transactions.isEmpty(); - } - - @Override - public boolean execute() { - return execute(false); - } - - @Override - public boolean execute(boolean force) { - if (this.hasExecuted || (!force && !this.canExecute())) { - return false; - } - - InventoryTransactionEvent ev = new InventoryTransactionEvent(this); - Server.getInstance().getPluginManager().callEvent(ev); - if (ev.isCancelled()) { - for (Inventory inventory : this.inventories) { - if (inventory instanceof PlayerInventory) { - ((PlayerInventory) inventory).sendArmorContents(this.getSource()); - } - inventory.sendContents(this.getSource()); - } - return false; - } - - for (Transaction transaction : this.transactions) { - transaction.getInventory().setItem(transaction.getSlot(), transaction.getTargetItem()); - } - - this.hasExecuted = true; - - return true; - } - - @Override - public boolean hasExecuted() { - return this.hasExecuted; - } -} diff --git a/src/main/java/cn/nukkit/inventory/Transaction.java b/src/main/java/cn/nukkit/inventory/Transaction.java deleted file mode 100644 index 5d20235803..0000000000 --- a/src/main/java/cn/nukkit/inventory/Transaction.java +++ /dev/null @@ -1,20 +0,0 @@ -package cn.nukkit.inventory; - -import cn.nukkit.item.Item; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public interface Transaction { - - Inventory getInventory(); - - int getSlot(); - - Item getSourceItem(); - - Item getTargetItem(); - - long getCreationTime(); -} diff --git a/src/main/java/cn/nukkit/inventory/TransactionGroup.java b/src/main/java/cn/nukkit/inventory/TransactionGroup.java deleted file mode 100644 index 5e71cf53a2..0000000000 --- a/src/main/java/cn/nukkit/inventory/TransactionGroup.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.nukkit.inventory; - -import java.util.Set; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public interface TransactionGroup { - - long getCreationTime(); - - Set getTransactions(); - - Set getInventories(); - - void addTransaction(Transaction transaction); - - boolean canExecute(); - - boolean execute(); - - boolean execute(boolean force); - - boolean hasExecuted(); -} diff --git a/src/main/java/cn/nukkit/inventory/transaction/InventoryTransaction.java b/src/main/java/cn/nukkit/inventory/transaction/InventoryTransaction.java new file mode 100644 index 0000000000..4496afc5b3 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/InventoryTransaction.java @@ -0,0 +1,26 @@ +package cn.nukkit.inventory.transaction; + +import cn.nukkit.inventory.Inventory; +import cn.nukkit.inventory.transaction.action.InventoryAction; + +import java.util.Set; + +/** + * @author CreeperFace + */ +public interface InventoryTransaction { + + long getCreationTime(); + + Set getActions(); + + Set getInventories(); + + void addAction(InventoryAction action); + + boolean canExecute(); + + boolean execute(); + + boolean hasExecuted(); +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/SimpleInventoryTransaction.java b/src/main/java/cn/nukkit/inventory/transaction/SimpleInventoryTransaction.java new file mode 100644 index 0000000000..48df171900 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/SimpleInventoryTransaction.java @@ -0,0 +1,252 @@ +package cn.nukkit.inventory.transaction; + +import cn.nukkit.Player; +import cn.nukkit.Server; +import cn.nukkit.event.inventory.InventoryTransactionEvent; +import cn.nukkit.inventory.Inventory; +import cn.nukkit.inventory.transaction.action.InventoryAction; +import cn.nukkit.inventory.transaction.action.SlotChangeAction; +import cn.nukkit.item.Item; +import cn.nukkit.utils.MainLogger; + +import java.util.*; +import java.util.Map.Entry; + +/** + * @author CreeperFace + */ +public class SimpleInventoryTransaction implements InventoryTransaction { + + private long creationTime; + protected boolean hasExecuted; + + protected Player source; + + protected Set inventories = new HashSet<>(); + + protected Set actions = new HashSet<>(); + + public SimpleInventoryTransaction(Player source, List actions) { + creationTime = System.currentTimeMillis(); + this.source = source; + + for (InventoryAction action : actions) { + this.addAction(action); + } + } + + public Player getSource() { + return source; + } + + @Override + public long getCreationTime() { + return creationTime; + } + + @Override + public Set getInventories() { + return inventories; + } + + @Override + public Set getActions() { + return actions; + } + + public void addAction(InventoryAction action) { + if (this.actions.contains(action)) { + return; + } + + if (action instanceof SlotChangeAction) { + this.inventories.add(((SlotChangeAction) action).getInventory()); + } + + this.actions.add(action); + } + + protected boolean matchItems(List needItems, List haveItems) { + for (InventoryAction action : this.actions) { + if (action.getTargetItem().getId() != Item.AIR) { + needItems.add(action.getTargetItem()); + } + + if (!action.isValid(this.source)) { + return false; + } + + if (action.getSourceItem().getId() != Item.AIR) { + haveItems.add(action.getSourceItem()); + } + } + + for (Item needItem : new ArrayList<>(needItems)) { + for (Item haveItem : new ArrayList<>(haveItems)) { + if (needItem.equals(haveItem)) { + int amount = Math.min(haveItem.getCount(), needItem.getCount()); + needItem.setCount(needItem.getCount() - amount); + haveItem.setCount(haveItem.getCount() - amount); + if (haveItem.getCount() == 0) { + haveItems.remove(haveItem); + } + if (needItem.getCount() == 0) { + needItems.remove(needItem); + break; + } + } + } + } + + return haveItems.isEmpty() && needItems.isEmpty(); + } + + /** + * Iterates over SlotChangeActions in this transaction and compacts any which refer to the same inventorySlot in the same + * inventory so they can be correctly handled. + *

+ * Under normal circumstances, the same inventorySlot would never be changed more than once in a single transaction. However, + * due to the way things like the crafting grid are "implemented" in MCPE 1.2 (a.k.a. hacked-in), we may get + * multiple inventorySlot changes referring to the same inventorySlot in a single transaction. These multiples are not even guaranteed + * to be in the correct order (inventorySlot splitting in the crafting grid for example, causes the actions to be sent in the + * wrong order), so this method also tries to chain them into order. + * + * @return bool + */ + protected boolean squashDuplicateSlotChanges() { + Map> slotChanges = new HashMap<>(); + + for (InventoryAction action : this.actions) { + if (action instanceof SlotChangeAction) { + int hash = Objects.hash(((SlotChangeAction) action).getInventory(), ((SlotChangeAction) action).getSlot()); + + List list = slotChanges.get(hash); + if (list == null) { + list = new ArrayList<>(); + } + + list.add((SlotChangeAction) action); + + slotChanges.put(hash, list); + } + } + + for (Entry> entry : new ArrayList<>(slotChanges.entrySet())) { + int hash = entry.getKey(); + List list = entry.getValue(); + + if (list.size() == 1) { //No need to compact inventorySlot changes if there is only one on this inventorySlot + slotChanges.remove(hash); + continue; + } + + List originalList = new ArrayList<>(list); + + SlotChangeAction originalAction = null; + Item lastTargetItem = null; + + for (int i = 0; i < list.size(); i++) { + SlotChangeAction action = list.get(i); + + if (action.isValid(this.source)) { + originalAction = action; + lastTargetItem = action.getTargetItem(); + list.remove(i); + break; + } + } + + if (originalAction == null) { + return false; //Couldn't find any actions that had a source-item matching the current inventory inventorySlot + } + + int sortedThisLoop; + + do { + sortedThisLoop = 0; + for (int i = 0; i < list.size(); i++) { + SlotChangeAction action = list.get(i); + + Item actionSource = action.getSourceItem(); + if (actionSource.equalsExact(lastTargetItem)) { + lastTargetItem = action.getTargetItem(); + list.remove(i); + sortedThisLoop++; + } + else if (actionSource.equals(lastTargetItem)) { + lastTargetItem.count -= actionSource.count; + list.remove(i); + if (lastTargetItem.count == 0) sortedThisLoop++; + } + } + } while (sortedThisLoop > 0); + + if (list.size() > 0) { //couldn't chain all the actions together + MainLogger.getLogger().debug("Failed to compact " + originalList.size() + " actions for " + this.source.getName()); + return false; + } + + for (SlotChangeAction action : originalList) { + this.actions.remove(action); + } + + this.addAction(new SlotChangeAction(originalAction.getInventory(), originalAction.getSlot(), originalAction.getSourceItem(), lastTargetItem)); + + MainLogger.getLogger().debug("Successfully compacted " + originalList.size() + " actions for " + this.source.getName()); + } + + return true; + } + + public boolean canExecute() { + this.squashDuplicateSlotChanges(); + + List haveItems = new ArrayList<>(); + List needItems = new ArrayList<>(); + return matchItems(needItems, haveItems) && this.actions.size() > 0 && haveItems.size() == 0 && needItems.size() == 0; + } + + /** + * @return bool + */ + public boolean execute() { + if (this.hasExecuted() || !this.canExecute()) { + return false; + } + + InventoryTransactionEvent ev = new InventoryTransactionEvent(this); + Server.getInstance().getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + this.handleFailed(); + return true; + } + + for (InventoryAction action : this.actions) { + if (!action.onPreExecute(this.source)) { + this.handleFailed(); + return true; + } + } + + for (InventoryAction action : this.actions) { + if (action.execute(this.source)) { + action.onExecuteSuccess(this.source); + } else { + action.onExecuteFail(this.source); + } + } + + this.hasExecuted = true; + return true; + } + + protected void handleFailed() { + for (InventoryAction action : this.actions) { + action.onExecuteFail(this.source); + } + } + + public boolean hasExecuted() { + return this.hasExecuted; + } +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/action/CreativeInventoryAction.java b/src/main/java/cn/nukkit/inventory/transaction/action/CreativeInventoryAction.java new file mode 100644 index 0000000000..eaa94eec75 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/action/CreativeInventoryAction.java @@ -0,0 +1,54 @@ +package cn.nukkit.inventory.transaction.action; + +import cn.nukkit.Player; +import cn.nukkit.item.Item; + +/** + * @author CreeperFace + */ +public class CreativeInventoryAction extends InventoryAction { + /** + * Player put an item into the creative window to destroy it. + */ + public static final int TYPE_DELETE_ITEM = 0; + /** + * Player took an item from the creative window. + */ + public static final int TYPE_CREATE_ITEM = 1; + + protected int actionType; + + public CreativeInventoryAction(Item source, Item target, int action) { + super(source, target); + } + + /** + * Checks that the player is in creative, and (if creating an item) that the item exists in the creative inventory. + */ + public boolean isValid(Player source) { + return source.isCreative() && + (this.actionType == TYPE_DELETE_ITEM || Item.getCreativeItemIndex(this.sourceItem) != -1); + } + + /** + * Returns the type of the action. + */ + public int getActionType() { + return actionType; + } + + /** + * No need to do anything extra here: this type just provides a place for items to disappear or appear from. + */ + public boolean execute(Player source) { + return true; + } + + public void onExecuteSuccess(Player source) { + + } + + public void onExecuteFail(Player source) { + + } +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/action/DropItemAction.java b/src/main/java/cn/nukkit/inventory/transaction/action/DropItemAction.java new file mode 100644 index 0000000000..b2cdea9ddf --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/action/DropItemAction.java @@ -0,0 +1,49 @@ +package cn.nukkit.inventory.transaction.action; + +import cn.nukkit.Player; +import cn.nukkit.event.player.PlayerDropItemEvent; +import cn.nukkit.item.Item; + +/** + * @author CreeperFace + */ +public class DropItemAction extends InventoryAction { + + public DropItemAction(Item source, Item target) { + super(source, target); + } + + /** + * Verifies that the source item of a drop-item action must be air. This is not strictly necessary, just a sanity + * check. + */ + public boolean isValid(Player source) { + return this.sourceItem.isNull(); + } + + @Override + public boolean onPreExecute(Player source) { + PlayerDropItemEvent ev; + source.getServer().getPluginManager().callEvent(ev = new PlayerDropItemEvent(source, this.targetItem)); + if (ev.isCancelled()) { + return false; + } + + return true; + } + + /** + * Drops the target item in front of the player. + */ + public boolean execute(Player source) { + return source.dropItem(this.targetItem); + } + + public void onExecuteSuccess(Player source) { + + } + + public void onExecuteFail(Player source) { + + } +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/action/InventoryAction.java b/src/main/java/cn/nukkit/inventory/transaction/action/InventoryAction.java new file mode 100644 index 0000000000..e853cbe085 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/action/InventoryAction.java @@ -0,0 +1,74 @@ +package cn.nukkit.inventory.transaction.action; + +import cn.nukkit.Player; +import cn.nukkit.item.Item; + +/** + * @author CreeperFace + */ +public abstract class InventoryAction { + + + private long creationTime; + + protected Item sourceItem; + + protected Item targetItem; + + public InventoryAction(Item sourceItem, Item targetItem) { + this.sourceItem = sourceItem; + this.targetItem = targetItem; + + this.creationTime = System.currentTimeMillis(); + } + + public long getCreationTime() { + return creationTime; + } + + /** + * Returns the item that was present before the action took place. + * + * @return Item + */ + public Item getSourceItem() { + return sourceItem.clone(); + } + + /** + * Returns the item that the action attempted to replace the source item with. + */ + public Item getTargetItem() { + return targetItem.clone(); + } + + /** + * Called by inventory transactions before any actions are processed. If this returns false, the transaction will + * be cancelled. + */ + public boolean onPreExecute(Player source) { + return true; + } + + /** + * Returns whether this action is currently valid. This should perform any necessary sanity checks. + */ + abstract public boolean isValid(Player source); + + /** + * Performs actions needed to complete the inventory-action server-side. Returns if it was successful. Will return + * false if plugins cancelled events. This will only be called if the transaction which it is part of is considered + * valid. + */ + abstract public boolean execute(Player source); + + /** + * Performs additional actions when this inventory-action completed successfully. + */ + abstract public void onExecuteSuccess(Player $source); + + /** + * Performs additional actions when this inventory-action did not complete successfully. + */ + abstract public void onExecuteFail(Player source); +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/action/SlotChangeAction.java b/src/main/java/cn/nukkit/inventory/transaction/action/SlotChangeAction.java new file mode 100644 index 0000000000..e1e77987eb --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/action/SlotChangeAction.java @@ -0,0 +1,70 @@ +package cn.nukkit.inventory.transaction.action; + +import cn.nukkit.Player; +import cn.nukkit.inventory.Inventory; +import cn.nukkit.item.Item; + +import java.util.HashSet; +import java.util.Set; + +/** + * @author CreeperFace + */ +public class SlotChangeAction extends InventoryAction { + + protected Inventory inventory; + private int inventorySlot; + + public SlotChangeAction(Inventory inventory, int inventorySlot, Item sourceItem, Item targetItem) { + super(sourceItem, targetItem); + this.inventory = inventory; + this.inventorySlot = inventorySlot; + } + + /** + * Returns the inventory involved in this action. + */ + public Inventory getInventory() { + return this.inventory; + } + + /** + * Returns the inventorySlot in the inventory which this action modified. + */ + public int getSlot() { + return inventorySlot; + } + + /** + * Checks if the item in the inventory at the specified inventorySlot is the same as this action's source item. + */ + public boolean isValid(Player source) { + Item check = inventory.getItem(this.inventorySlot); + + return check.equalsExact(this.sourceItem); + } + + /** + * Sets the item into the target inventory. + */ + public boolean execute(Player source) { + return this.inventory.setItem(this.inventorySlot, this.targetItem, false); + } + + /** + * Sends inventorySlot changes to other viewers of the inventory. This will not send any change back to the source Player. + */ + public void onExecuteSuccess(Player source) { + Set viewers = new HashSet<>(this.inventory.getViewers()); + viewers.remove(source); + + this.inventory.sendSlot(this.inventorySlot, viewers); + } + + /** + * Sends the original inventorySlot contents to the source player to revert the action. + */ + public void onExecuteFail(Player source) { + this.inventory.sendSlot(this.inventorySlot, source); + } +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/data/ReleaseItemData.java b/src/main/java/cn/nukkit/inventory/transaction/data/ReleaseItemData.java new file mode 100644 index 0000000000..9ad8db1038 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/data/ReleaseItemData.java @@ -0,0 +1,15 @@ +package cn.nukkit.inventory.transaction.data; + +import cn.nukkit.item.Item; +import cn.nukkit.math.Vector3; + +/** + * @author CreeperFace + */ +public class ReleaseItemData implements TransactionData { + + public int actionType; + public int hotbarSlot; + public Item itemInHand; + public Vector3 headRot; +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/data/TransactionData.java b/src/main/java/cn/nukkit/inventory/transaction/data/TransactionData.java new file mode 100644 index 0000000000..f594453b90 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/data/TransactionData.java @@ -0,0 +1,7 @@ +package cn.nukkit.inventory.transaction.data; + +/** + * @author CreeperFace + */ +public interface TransactionData { +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/data/UseItemData.java b/src/main/java/cn/nukkit/inventory/transaction/data/UseItemData.java new file mode 100644 index 0000000000..00c5cae5e3 --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/data/UseItemData.java @@ -0,0 +1,22 @@ +package cn.nukkit.inventory.transaction.data; + +import cn.nukkit.item.Item; +import cn.nukkit.math.BlockFace; +import cn.nukkit.math.BlockVector3; +import cn.nukkit.math.Vector3; +import cn.nukkit.math.Vector3f; + +/** + * @author CreeperFace + */ +public class UseItemData implements TransactionData { + + public int actionType; + public BlockVector3 blockPos; + public BlockFace face; + public int hotbarSlot; + public Item itemInHand; + public Vector3 playerPos; + public Vector3f clickPos; + +} diff --git a/src/main/java/cn/nukkit/inventory/transaction/data/UseItemOnEntityData.java b/src/main/java/cn/nukkit/inventory/transaction/data/UseItemOnEntityData.java new file mode 100644 index 0000000000..ca09c09d0d --- /dev/null +++ b/src/main/java/cn/nukkit/inventory/transaction/data/UseItemOnEntityData.java @@ -0,0 +1,18 @@ +package cn.nukkit.inventory.transaction.data; + +import cn.nukkit.item.Item; +import cn.nukkit.math.Vector3; + +/** + * @author CreeperFace + */ +public class UseItemOnEntityData implements TransactionData { + + public long entityRuntimeId; + public int actionType; + public int hotbarSlot; + public Item itemInHand; + public Vector3 vector1; + public Vector3 vector2; + +} diff --git a/src/main/java/cn/nukkit/item/Item.java b/src/main/java/cn/nukkit/item/Item.java index 94235828a9..a1728c361d 100644 --- a/src/main/java/cn/nukkit/item/Item.java +++ b/src/main/java/cn/nukkit/item/Item.java @@ -1,27 +1,33 @@ package cn.nukkit.item; import cn.nukkit.Player; +import cn.nukkit.Server; import cn.nukkit.block.Block; import cn.nukkit.block.BlockAir; -import cn.nukkit.block.BlockFence; -import cn.nukkit.block.BlockFlower; import cn.nukkit.entity.Entity; import cn.nukkit.inventory.Fuel; import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.level.Level; import cn.nukkit.math.BlockFace; +import cn.nukkit.math.Vector3; import cn.nukkit.nbt.NBTIO; import cn.nukkit.nbt.tag.CompoundTag; import cn.nukkit.nbt.tag.ListTag; import cn.nukkit.nbt.tag.StringTag; import cn.nukkit.nbt.tag.Tag; import cn.nukkit.utils.Binary; +import cn.nukkit.utils.Config; +import cn.nukkit.utils.MainLogger; +import cn.nukkit.utils.Utils; +import javax.xml.bind.DatatypeConverter; +import java.io.File; import java.io.IOException; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Map; import java.util.regex.Pattern; /** @@ -30,22 +36,6 @@ */ public class Item implements Cloneable { - private static CompoundTag parseCompoundTag(byte[] tag) { - try { - return NBTIO.read(tag, ByteOrder.LITTLE_ENDIAN); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - private byte[] writeCompoundTag(CompoundTag tag) { - try { - return NBTIO.write(tag, ByteOrder.LITTLE_ENDIAN); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - //All Block IDs are here too public static final int AIR = 0; public static final int STONE = 1; @@ -160,7 +150,7 @@ private byte[] writeCompoundTag(CompoundTag tag) { public static final int CLAY_BLOCK = 82; public static final int REEDS = 83; public static final int SUGARCANE_BLOCK = 83; - + public static final int JUKEBOX = 84; public static final int FENCE = 85; public static final int PUMPKIN = 86; public static final int NETHERRACK = 87; @@ -311,6 +301,11 @@ private byte[] writeCompoundTag(CompoundTag tag) { public static final int END_ROD = 208; public static final int END_GATEWAY = 209; + public static final int MAGMA = 213; + public static final int BLOCK_NETHER_WART_BLOCK = 214; + public static final int RED_NETHER_BRICK = 215; + public static final int BONE_BLOCK = 216; + public static final int SHULKER_BOX = 218; public static final int PURPLE_GLAZED_TERRACOTTA = 219; public static final int WHITE_GLAZED_TERRACOTTA = 220; @@ -490,7 +485,8 @@ private byte[] writeCompoundTag(CompoundTag tag) { public static final int SPAWN_EGG = 383; public static final int EXPERIENCE_BOTTLE = 384; public static final int FIRE_CHARGE = 385; - + public static final int BOOK_AND_QUILL = 386; + public static final int WRITTEN_BOOK = 387; public static final int EMERALD = 388; public static final int ITEM_FRAME = 389; public static final int FLOWER_POT = 390; @@ -562,6 +558,19 @@ private byte[] writeCompoundTag(CompoundTag tag) { public static final int GOLDEN_APPLE_ENCHANTED = 466; + public static final int RECORD_13 = 500; + public static final int RECORD_CAT = 501; + public static final int RECORD_BLOCKS = 502; + public static final int RECORD_CHIRP = 503; + public static final int RECORD_FAR = 504; + public static final int RECORD_MALL = 505; + public static final int RECORD_MELLOHI = 506; + public static final int RECORD_STAL = 507; + public static final int RECORD_STRAD = 508; + public static final int RECORD_WARD = 509; + public static final int RECORD_11 = 510; + public static final int RECORD_WAIT = 511; + public static Class[] list = null; protected Block block = null; @@ -741,7 +750,8 @@ public static void init() { list[SPAWN_EGG] = ItemSpawnEgg.class; //383 list[EXPERIENCE_BOTTLE] = ItemExpBottle.class; //384 //TODO: list[FIRE_CHARGE] = ItemFireCharge.class; //385 - + //TODO: list[BOOK_AND_QUILL] = ItemBookAndQuill.class; //386 + list[WRITTEN_BOOK] = ItemBookWritten.class; //387 list[EMERALD] = ItemEmerald.class; //388 list[ITEM_FRAME] = ItemItemFrame.class; //389 list[FLOWER_POT] = ItemFlowerPot.class; //390 @@ -805,6 +815,18 @@ public static void init() { list[COOKED_SALMON] = ItemSalmonCooked.class; //463 list[GOLDEN_APPLE_ENCHANTED] = ItemAppleGoldEnchanted.class; //466 + /*list[RECORD_11] = ItemRecord11.class; + list[RECORD_CAT] = ItemRecordCat.class; + list[RECORD_13] = ItemRecord13.class; + list[RECORD_BLOCKS] = ItemRecordBlocks.class; + list[RECORD_CHIRP] = ItemRecordChirp.class; + list[RECORD_FAR] = ItemRecordFar.class; + list[RECORD_WARD] = ItemRecordWard.class; + list[RECORD_MALL] = ItemRecordMall.class; + list[RECORD_MELLOHI] = ItemRecordMellohi.class; + list[RECORD_STAL] = ItemRecordStal.class; + list[RECORD_STRAD] = ItemRecordStrad.class; + list[RECORD_WAIT] = ItemRecordWait.class;*/ for (int i = 0; i < 256; ++i) { if (Block.list[i] != null) { @@ -820,644 +842,31 @@ public static void init() { private static void initCreativeItems() { clearCreativeItems(); + Server server = Server.getInstance(); - //Building - addCreativeItem(Item.get(Item.COBBLESTONE, 0)); - addCreativeItem(Item.get(Item.STONE_BRICKS, 0)); - addCreativeItem(Item.get(Item.STONE_BRICKS, 1)); - addCreativeItem(Item.get(Item.STONE_BRICKS, 2)); - addCreativeItem(Item.get(Item.STONE_BRICKS, 3)); - addCreativeItem(Item.get(Item.MOSS_STONE, 0)); - addCreativeItem(Item.get(Item.WOODEN_PLANKS, 0)); - addCreativeItem(Item.get(Item.WOODEN_PLANKS, 1)); - addCreativeItem(Item.get(Item.WOODEN_PLANKS, 2)); - addCreativeItem(Item.get(Item.WOODEN_PLANKS, 3)); - addCreativeItem(Item.get(Item.WOODEN_PLANKS, 4)); - addCreativeItem(Item.get(Item.WOODEN_PLANKS, 5)); - addCreativeItem(Item.get(Item.BRICKS, 0)); - - addCreativeItem(Item.get(Item.STONE, 0)); - addCreativeItem(Item.get(Item.STONE, 1)); - addCreativeItem(Item.get(Item.STONE, 2)); - addCreativeItem(Item.get(Item.STONE, 3)); - addCreativeItem(Item.get(Item.STONE, 4)); - addCreativeItem(Item.get(Item.STONE, 5)); - addCreativeItem(Item.get(Item.STONE, 6)); - addCreativeItem(Item.get(Item.DIRT, 0)); - addCreativeItem(Item.get(Item.PODZOL, 0)); - addCreativeItem(Item.get(Item.GRASS, 0)); - addCreativeItem(Item.get(Item.MYCELIUM, 0)); - addCreativeItem(Item.get(Item.CLAY_BLOCK, 0)); - addCreativeItem(Item.get(Item.TERRACOTTA, 0)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 0)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 1)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 2)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 3)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 4)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 5)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 6)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 7)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 8)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 9)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 10)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 11)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 12)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 13)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 14)); - addCreativeItem(Item.get(Item.STAINED_TERRACOTTA, 15)); - addCreativeItem(Item.get(Item.SANDSTONE, 0)); - addCreativeItem(Item.get(Item.SANDSTONE, 1)); - addCreativeItem(Item.get(Item.SANDSTONE, 2)); - addCreativeItem(Item.get(Item.RED_SANDSTONE, 0)); - addCreativeItem(Item.get(Item.RED_SANDSTONE, 1)); - addCreativeItem(Item.get(Item.RED_SANDSTONE, 2)); - addCreativeItem(Item.get(Item.SAND, 0)); - addCreativeItem(Item.get(Item.SAND, 1)); - addCreativeItem(Item.get(Item.GRAVEL, 0)); - addCreativeItem(Item.get(Item.TRUNK, 0)); - addCreativeItem(Item.get(Item.TRUNK, 1)); - addCreativeItem(Item.get(Item.TRUNK, 2)); - addCreativeItem(Item.get(Item.TRUNK, 3)); - addCreativeItem(Item.get(Item.TRUNK2, 0)); - addCreativeItem(Item.get(Item.TRUNK2, 1)); - addCreativeItem(Item.get(Item.NETHER_BRICKS, 0)); - addCreativeItem(Item.get(Item.NETHERRACK, 0)); - addCreativeItem(Item.get(Item.SOUL_SAND, 0)); - addCreativeItem(Item.get(Item.BEDROCK, 0)); - addCreativeItem(Item.get(Item.COBBLESTONE_STAIRS, 0)); - addCreativeItem(Item.get(Item.OAK_WOODEN_STAIRS, 0)); - addCreativeItem(Item.get(Item.SPRUCE_WOODEN_STAIRS, 0)); - addCreativeItem(Item.get(Item.BIRCH_WOODEN_STAIRS, 0)); - addCreativeItem(Item.get(Item.JUNGLE_WOODEN_STAIRS, 0)); - addCreativeItem(Item.get(Item.ACACIA_WOODEN_STAIRS, 0)); - addCreativeItem(Item.get(Item.DARK_OAK_WOODEN_STAIRS, 0)); - addCreativeItem(Item.get(Item.BRICK_STAIRS, 0)); - addCreativeItem(Item.get(Item.SANDSTONE_STAIRS, 0)); - addCreativeItem(Item.get(Item.RED_SANDSTONE_STAIRS, 0)); - addCreativeItem(Item.get(Item.STONE_BRICK_STAIRS, 0)); - addCreativeItem(Item.get(Item.NETHER_BRICKS_STAIRS, 0)); - addCreativeItem(Item.get(Item.QUARTZ_STAIRS, 0)); - addCreativeItem(Item.get(Item.PURPUR_STAIRS, 0)); - addCreativeItem(Item.get(Item.SLAB, 0)); - addCreativeItem(Item.get(Item.SLAB, 3)); - addCreativeItem(Item.get(Item.WOODEN_SLAB, 0)); - addCreativeItem(Item.get(Item.WOODEN_SLAB, 1)); - addCreativeItem(Item.get(Item.WOODEN_SLAB, 2)); - addCreativeItem(Item.get(Item.WOODEN_SLAB, 3)); - addCreativeItem(Item.get(Item.WOODEN_SLAB, 4)); - addCreativeItem(Item.get(Item.WOODEN_SLAB, 5)); - addCreativeItem(Item.get(Item.SLAB, 4)); - addCreativeItem(Item.get(Item.SLAB, 1)); - addCreativeItem(Item.get(Item.RED_SANDSTONE_SLAB)); - addCreativeItem(Item.get(Item.SLAB, 5)); - addCreativeItem(Item.get(Item.SLAB, 7)); - addCreativeItem(Item.get(Item.SLAB, 6)); - addCreativeItem(Item.get(Item.RED_SANDSTONE_SLAB, 1)); - addCreativeItem(Item.get(Item.QUARTZ_BLOCK, 0)); - addCreativeItem(Item.get(Item.QUARTZ_BLOCK, 2)); - addCreativeItem(Item.get(Item.QUARTZ_BLOCK, 1)); - addCreativeItem(Item.get(Item.PRISMARINE, 0)); - addCreativeItem(Item.get(Item.PRISMARINE, 1)); - addCreativeItem(Item.get(Item.PRISMARINE, 2)); - addCreativeItem(Item.get(Item.PURPUR_BLOCK, 0)); - addCreativeItem(Item.get(Item.PURPUR_BLOCK, 2)); - addCreativeItem(Item.get(Item.COAL_ORE, 0)); - addCreativeItem(Item.get(Item.IRON_ORE, 0)); - addCreativeItem(Item.get(Item.GOLD_ORE, 0)); - addCreativeItem(Item.get(Item.DIAMOND_ORE, 0)); - addCreativeItem(Item.get(Item.LAPIS_ORE, 0)); - addCreativeItem(Item.get(Item.REDSTONE_ORE, 0)); - addCreativeItem(Item.get(Item.EMERALD_ORE, 0)); - addCreativeItem(Item.get(Item.QUARTZ_ORE, 0)); - addCreativeItem(Item.get(Item.OBSIDIAN, 0)); - addCreativeItem(Item.get(Item.ICE, 0)); - addCreativeItem(Item.get(Item.PACKED_ICE, 0)); - addCreativeItem(Item.get(Item.SNOW_BLOCK, 0)); - addCreativeItem(Item.get(Item.END_BRICKS, 0)); - addCreativeItem(Item.get(Item.END_STONE, 0)); - - //Decoration - addCreativeItem(Item.get(Item.BEACON, 0)); - addCreativeItem(Item.get(Item.COBBLESTONE_WALL, 0)); - addCreativeItem(Item.get(Item.COBBLESTONE_WALL, 1)); - addCreativeItem(Item.get(Item.WATER_LILY, 0)); - addCreativeItem(Item.get(Item.SEA_LANTERN, 0)); - addCreativeItem(Item.get(Item.CHORUS_PLANT, 0)); - addCreativeItem(Item.get(Item.CHORUS_FLOWER, 0)); - addCreativeItem(Item.get(Item.GOLD_BLOCK, 0)); - addCreativeItem(Item.get(Item.IRON_BLOCK, 0)); - addCreativeItem(Item.get(Item.DIAMOND_BLOCK, 0)); - addCreativeItem(Item.get(Item.LAPIS_BLOCK, 0)); - addCreativeItem(Item.get(Item.COAL_BLOCK, 0)); - addCreativeItem(Item.get(Item.EMERALD_BLOCK, 0)); - addCreativeItem(Item.get(Item.REDSTONE_BLOCK, 0)); - addCreativeItem(Item.get(Item.SNOW_LAYER, 0)); - addCreativeItem(Item.get(Item.GLASS, 0)); - addCreativeItem(Item.get(Item.GLOWSTONE_BLOCK, 0)); - addCreativeItem(Item.get(Item.VINES, 0)); - addCreativeItem(Item.get(Item.LADDER, 0)); - addCreativeItem(Item.get(Item.SPONGE, 0)); - addCreativeItem(Item.get(Item.SPONGE, 1)); - addCreativeItem(Item.get(Item.GLASS_PANE, 0)); - addCreativeItem(Item.get(Item.WOODEN_DOOR, 0)); - addCreativeItem(Item.get(Item.SPRUCE_DOOR, 0)); - addCreativeItem(Item.get(Item.BIRCH_DOOR, 0)); - addCreativeItem(Item.get(Item.JUNGLE_DOOR, 0)); - addCreativeItem(Item.get(Item.ACACIA_DOOR, 0)); - addCreativeItem(Item.get(Item.DARK_OAK_DOOR, 0)); - addCreativeItem(Item.get(Item.IRON_DOOR, 0)); - addCreativeItem(Item.get(Item.TRAPDOOR, 0)); - addCreativeItem(Item.get(Item.IRON_TRAPDOOR, 0)); - addCreativeItem(Item.get(Item.FENCE, BlockFence.FENCE_OAK)); - addCreativeItem(Item.get(Item.FENCE, BlockFence.FENCE_SPRUCE)); - addCreativeItem(Item.get(Item.FENCE, BlockFence.FENCE_BIRCH)); - addCreativeItem(Item.get(Item.FENCE, BlockFence.FENCE_JUNGLE)); - addCreativeItem(Item.get(Item.FENCE, BlockFence.FENCE_ACACIA)); - addCreativeItem(Item.get(Item.FENCE, BlockFence.FENCE_DARK_OAK)); - addCreativeItem(Item.get(Item.NETHER_BRICK_FENCE, 0)); - addCreativeItem(Item.get(Item.FENCE_GATE, 0)); - addCreativeItem(Item.get(Item.FENCE_GATE_SPRUCE, 0)); - addCreativeItem(Item.get(Item.FENCE_GATE_BIRCH, 0)); - addCreativeItem(Item.get(Item.FENCE_GATE_JUNGLE, 0)); - addCreativeItem(Item.get(Item.FENCE_GATE_ACACIA, 0)); - addCreativeItem(Item.get(Item.FENCE_GATE_DARK_OAK, 0)); - addCreativeItem(Item.get(Item.IRON_BARS, 0)); - int[] dyeColors = {0, 8, 7, 15, 12, 14, 1, 4, 5, 13, 9, 3, 11, 10, 2, 6}; - for (int color : dyeColors) { - addCreativeItem(Item.get(Item.BED, color)); - } - addCreativeItem(Item.get(Item.BOOKSHELF, 0)); - addCreativeItem(Item.get(Item.SIGN, 0)); - addCreativeItem(Item.get(Item.PAINTING, 0)); - addCreativeItem(Item.get(Item.ITEM_FRAME, 0)); - addCreativeItem(Item.get(Item.WORKBENCH, 0)); - addCreativeItem(Item.get(Item.STONECUTTER, 0)); - addCreativeItem(Item.get(Item.CHEST, 0)); - addCreativeItem(Item.get(Item.TRAPPED_CHEST, 0)); - addCreativeItem(Item.get(Item.FURNACE, 0)); - addCreativeItem(Item.get(Item.BREWING_STAND, 0)); - addCreativeItem(Item.get(Item.CAULDRON, 0)); - addCreativeItem(Item.get(Item.NOTEBLOCK, 0)); - addCreativeItem(Item.get(Item.END_ROD, 0)); - addCreativeItem(Item.get(Item.END_PORTAL_FRAME, 0)); - addCreativeItem(Item.get(Item.ANVIL, 0)); - addCreativeItem(Item.get(Item.ANVIL, 4)); - addCreativeItem(Item.get(Item.ANVIL, 8)); - addCreativeItem(Item.get(Item.DANDELION, 0)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_POPPY)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_BLUE_ORCHID)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_ALLIUM)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_AZURE_BLUET)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_RED_TULIP)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_ORANGE_TULIP)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_WHITE_TULIP)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_PINK_TULIP)); - addCreativeItem(Item.get(Item.RED_FLOWER, BlockFlower.TYPE_OXEYE_DAISY)); - addCreativeItem(Item.get(Item.DOUBLE_PLANT, 0)); // SUNFLOWER - addCreativeItem(Item.get(Item.DOUBLE_PLANT, 1)); // Lilac - addCreativeItem(Item.get(Item.DOUBLE_PLANT, 2)); // Double Tall Grass - addCreativeItem(Item.get(Item.DOUBLE_PLANT, 3)); // Large fern - addCreativeItem(Item.get(Item.DOUBLE_PLANT, 4)); // Rose bush - addCreativeItem(Item.get(Item.DOUBLE_PLANT, 5)); // Peony - addCreativeItem(Item.get(Item.BROWN_MUSHROOM, 0)); - addCreativeItem(Item.get(Item.RED_MUSHROOM, 0)); - addCreativeItem(Item.get(Item.BROWN_MUSHROOM_BLOCK, 14)); - addCreativeItem(Item.get(Item.RED_MUSHROOM_BLOCK, 14)); - addCreativeItem(Item.get(Item.BROWN_MUSHROOM_BLOCK, 0)); - addCreativeItem(Item.get(Item.RED_MUSHROOM_BLOCK, 15)); - addCreativeItem(Item.get(Item.CACTUS, 0)); - addCreativeItem(Item.get(Item.MELON_BLOCK, 0)); - addCreativeItem(Item.get(Item.PUMPKIN, 0)); - addCreativeItem(Item.get(Item.LIT_PUMPKIN, 0)); - addCreativeItem(Item.get(Item.COBWEB, 0)); - addCreativeItem(Item.get(Item.HAY_BALE, 0)); - addCreativeItem(Item.get(Item.TALL_GRASS, 1)); - addCreativeItem(Item.get(Item.TALL_GRASS, 2)); - addCreativeItem(Item.get(Item.DEAD_BUSH, 0)); - addCreativeItem(Item.get(Item.SAPLING, 0)); - addCreativeItem(Item.get(Item.SAPLING, 1)); - addCreativeItem(Item.get(Item.SAPLING, 2)); - addCreativeItem(Item.get(Item.SAPLING, 3)); - addCreativeItem(Item.get(Item.SAPLING, 4)); - addCreativeItem(Item.get(Item.SAPLING, 5)); - addCreativeItem(Item.get(Item.LEAVES, 0)); - addCreativeItem(Item.get(Item.LEAVES, 1)); - addCreativeItem(Item.get(Item.LEAVES, 2)); - addCreativeItem(Item.get(Item.LEAVES, 3)); - addCreativeItem(Item.get(Item.LEAVES2, 0)); - addCreativeItem(Item.get(Item.LEAVES2, 1)); - - addCreativeItem(Item.get(Item.WHITE_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.SILVER_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.GRAY_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.BLACK_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.BROWN_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.RED_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.ORANGE_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.LIME_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.GREEN_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.CYAN_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.LIGHT_BLUE_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.BLUE_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.PURPLE_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.MAGENTA_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.WHITE_GLAZED_TERRACOTTA)); - addCreativeItem(Item.get(Item.PINK_GLAZED_TERRACOTTA)); - - addCreativeItem(Item.get(Item.CAKE, 0)); - - addCreativeItem(Item.get(Item.SKULL, ItemSkull.SKELETON_SKULL)); - addCreativeItem(Item.get(Item.SKULL, ItemSkull.WITHER_SKELETON_SKULL)); - addCreativeItem(Item.get(Item.SKULL, ItemSkull.ZOMBIE_HEAD)); - addCreativeItem(Item.get(Item.SKULL, ItemSkull.HEAD)); - addCreativeItem(Item.get(Item.SKULL, ItemSkull.CREEPER_HEAD)); - addCreativeItem(Item.get(Item.SKULL, ItemSkull.DRAGON_HEAD)); - - addCreativeItem(Item.get(Item.FLOWER_POT, 0)); - - addCreativeItem(Item.get(Item.MONSTER_EGG, 0)); - addCreativeItem(Item.get(Item.MONSTER_EGG, 1)); - addCreativeItem(Item.get(Item.MONSTER_EGG, 2)); - addCreativeItem(Item.get(Item.MONSTER_EGG, 3)); - addCreativeItem(Item.get(Item.MONSTER_EGG, 4)); - addCreativeItem(Item.get(Item.MONSTER_EGG, 5)); - - addCreativeItem(Item.get(Item.DRAGON_EGG, 0)); - addCreativeItem(Item.get(Item.END_CRYSTAL, 0)); - addCreativeItem(Item.get(Item.MONSTER_SPAWNER, 0)); - addCreativeItem(Item.get(Item.ENCHANTMENT_TABLE, 0)); - addCreativeItem(Item.get(Item.SLIME_BLOCK, 0)); - addCreativeItem(Item.get(Item.ENDER_CHEST, 0)); - - for (int color : dyeColors) { - addCreativeItem(Item.get(Item.WOOL, color)); + String path = server.getDataPath() + "creativeitems.json"; + if (!new File(path).exists()) { + try { + Utils.writeFile(path, Server.class.getClassLoader().getResourceAsStream("creativeitems.json")); + } catch (IOException e) { + MainLogger.getLogger().logException(e); + return; + } } + List list = new Config(path, Config.YAML).getMapList("items"); - addCreativeItem(Item.get(Item.CARPET, 0)); - addCreativeItem(Item.get(Item.CARPET, 8)); - addCreativeItem(Item.get(Item.CARPET, 7)); - addCreativeItem(Item.get(Item.CARPET, 15)); - addCreativeItem(Item.get(Item.CARPET, 12)); - addCreativeItem(Item.get(Item.CARPET, 14)); - addCreativeItem(Item.get(Item.CARPET, 1)); - addCreativeItem(Item.get(Item.CARPET, 4)); - addCreativeItem(Item.get(Item.CARPET, 5)); - addCreativeItem(Item.get(Item.CARPET, 13)); - addCreativeItem(Item.get(Item.CARPET, 9)); - addCreativeItem(Item.get(Item.CARPET, 3)); - addCreativeItem(Item.get(Item.CARPET, 11)); - addCreativeItem(Item.get(Item.CARPET, 10)); - addCreativeItem(Item.get(Item.CARPET, 2)); - addCreativeItem(Item.get(Item.CARPET, 6)); - - - //Tools - addCreativeItem(Item.get(Item.RAIL, 0)); - addCreativeItem(Item.get(Item.POWERED_RAIL, 0)); - addCreativeItem(Item.get(Item.DETECTOR_RAIL, 0)); - addCreativeItem(Item.get(Item.ACTIVATOR_RAIL, 0)); - addCreativeItem(Item.get(Item.TORCH, 0)); - addCreativeItem(Item.get(Item.BUCKET, 0)); - addCreativeItem(Item.get(Item.BUCKET, 1)); // milk - addCreativeItem(Item.get(Item.BUCKET, 8)); // water - addCreativeItem(Item.get(Item.BUCKET, 10)); // lava - addCreativeItem(Item.get(Item.TNT, 0)); - addCreativeItem(Item.get(Item.LEAD, 0)); - addCreativeItem(Item.get(Item.NAME_TAG, 0)); - addCreativeItem(Item.get(Item.REDSTONE, 0)); - addCreativeItem(Item.get(Item.BOW, 0)); - addCreativeItem(Item.get(Item.FISHING_ROD, 0)); - addCreativeItem(Item.get(Item.FLINT_AND_STEEL, 0)); - addCreativeItem(Item.get(Item.SHEARS, 0)); - addCreativeItem(Item.get(Item.CLOCK, 0)); - addCreativeItem(Item.get(Item.COMPASS, 0)); - addCreativeItem(Item.get(Item.MINECART, 0)); - addCreativeItem(Item.get(Item.MINECART_WITH_CHEST, 0)); - addCreativeItem(Item.get(Item.MINECART_WITH_HOPPER, 0)); - addCreativeItem(Item.get(Item.MINECART_WITH_TNT, 0)); - addCreativeItem(Item.get(Item.BOAT, 0)); // Oak - addCreativeItem(Item.get(Item.BOAT, 1)); // Spruce - addCreativeItem(Item.get(Item.BOAT, 2)); // Birch - addCreativeItem(Item.get(Item.BOAT, 3)); // Jungle - addCreativeItem(Item.get(Item.BOAT, 4)); // Acacia - addCreativeItem(Item.get(Item.BOAT, 5)); // Dark Oak - addCreativeItem(Item.get(Item.SADDLE, 0)); - addCreativeItem(Item.get(Item.LEATHER_HORSE_ARMOR, 0)); - addCreativeItem(Item.get(Item.IRON_HORSE_ARMOR, 0)); - addCreativeItem(Item.get(Item.GOLD_HORSE_ARMOR, 0)); - addCreativeItem(Item.get(Item.DIAMOND_HORSE_ARMOR, 0)); - - addCreativeItem(Item.get(Item.SPAWN_EGG, 10)); //Chicken - addCreativeItem(Item.get(Item.SPAWN_EGG, 11)); //Cow - addCreativeItem(Item.get(Item.SPAWN_EGG, 12)); //Pig - addCreativeItem(Item.get(Item.SPAWN_EGG, 13)); //Sheep - addCreativeItem(Item.get(Item.SPAWN_EGG, 15)); //Villager - addCreativeItem(Item.get(Item.SPAWN_EGG, 16)); //Mooshroom - addCreativeItem(Item.get(Item.SPAWN_EGG, 17)); //Squid - addCreativeItem(Item.get(Item.SPAWN_EGG, 19)); //Bat - //addCreativeItem(Item.get(Item.SPAWN_EGG, 20)); //Iron Golem - //addCreativeItem(Item.get(Item.SPAWN_EGG, 21)); //Snow Golem - addCreativeItem(Item.get(Item.SPAWN_EGG, 22)); //Ocelot - addCreativeItem(Item.get(Item.SPAWN_EGG, 23)); //Horse - addCreativeItem(Item.get(Item.SPAWN_EGG, 24)); //Donkey - addCreativeItem(Item.get(Item.SPAWN_EGG, 25)); //Mule - addCreativeItem(Item.get(Item.SPAWN_EGG, 26)); //SkeletonHorse - addCreativeItem(Item.get(Item.SPAWN_EGG, 27)); //ZombieHorse - addCreativeItem(Item.get(Item.SPAWN_EGG, 28)); //PolarBear - addCreativeItem(Item.get(Item.SPAWN_EGG, 29)); //Llama - addCreativeItem(Item.get(Item.SPAWN_EGG, 32)); //Zombie - addCreativeItem(Item.get(Item.SPAWN_EGG, 33)); //Creeper - addCreativeItem(Item.get(Item.SPAWN_EGG, 34)); //Skeleton - addCreativeItem(Item.get(Item.SPAWN_EGG, 35)); //Spider - addCreativeItem(Item.get(Item.SPAWN_EGG, 36)); //Zombie Pigman - addCreativeItem(Item.get(Item.SPAWN_EGG, 37)); //Slime - addCreativeItem(Item.get(Item.SPAWN_EGG, 38)); //Enderman - addCreativeItem(Item.get(Item.SPAWN_EGG, 39)); //Silverfish - addCreativeItem(Item.get(Item.SPAWN_EGG, 40)); //Cave spider - addCreativeItem(Item.get(Item.SPAWN_EGG, 41)); //Ghast - addCreativeItem(Item.get(Item.SPAWN_EGG, 42)); //MagmaCube - addCreativeItem(Item.get(Item.SPAWN_EGG, 43)); //Blaze - addCreativeItem(Item.get(Item.SPAWN_EGG, 45)); //Witch - addCreativeItem(Item.get(Item.SPAWN_EGG, 46)); //Stray - addCreativeItem(Item.get(Item.SPAWN_EGG, 47)); //Husk - addCreativeItem(Item.get(Item.SPAWN_EGG, 49)); //Guardian - addCreativeItem(Item.get(Item.SPAWN_EGG, 50)); //ElderGuardian - addCreativeItem(Item.get(Item.SPAWN_EGG, 54)); //Shulker - - addCreativeItem(Item.get(Item.FIRE_CHARGE, 0)); - addCreativeItem(Item.get(Item.WOODEN_SWORD)); - addCreativeItem(Item.get(Item.WOODEN_HOE)); - addCreativeItem(Item.get(Item.WOODEN_SHOVEL)); - addCreativeItem(Item.get(Item.WOODEN_PICKAXE)); - addCreativeItem(Item.get(Item.WOODEN_AXE)); - addCreativeItem(Item.get(Item.STONE_SWORD)); - addCreativeItem(Item.get(Item.STONE_HOE)); - addCreativeItem(Item.get(Item.STONE_SHOVEL)); - addCreativeItem(Item.get(Item.STONE_PICKAXE)); - addCreativeItem(Item.get(Item.STONE_AXE)); - addCreativeItem(Item.get(Item.IRON_SWORD)); - addCreativeItem(Item.get(Item.IRON_HOE)); - addCreativeItem(Item.get(Item.IRON_SHOVEL)); - addCreativeItem(Item.get(Item.IRON_PICKAXE)); - addCreativeItem(Item.get(Item.IRON_AXE)); - addCreativeItem(Item.get(Item.DIAMOND_SWORD)); - addCreativeItem(Item.get(Item.DIAMOND_HOE)); - addCreativeItem(Item.get(Item.DIAMOND_SHOVEL)); - addCreativeItem(Item.get(Item.DIAMOND_PICKAXE)); - addCreativeItem(Item.get(Item.DIAMOND_AXE)); - addCreativeItem(Item.get(Item.GOLD_SWORD)); - addCreativeItem(Item.get(Item.GOLD_HOE)); - addCreativeItem(Item.get(Item.GOLD_SHOVEL)); - addCreativeItem(Item.get(Item.GOLD_PICKAXE)); - addCreativeItem(Item.get(Item.GOLD_AXE)); - addCreativeItem(Item.get(Item.LEATHER_CAP)); - addCreativeItem(Item.get(Item.LEATHER_TUNIC)); - addCreativeItem(Item.get(Item.LEATHER_PANTS)); - addCreativeItem(Item.get(Item.LEATHER_BOOTS)); - addCreativeItem(Item.get(Item.CHAIN_HELMET)); - addCreativeItem(Item.get(Item.CHAIN_CHESTPLATE)); - addCreativeItem(Item.get(Item.CHAIN_LEGGINGS)); - addCreativeItem(Item.get(Item.CHAIN_BOOTS)); - addCreativeItem(Item.get(Item.IRON_HELMET)); - addCreativeItem(Item.get(Item.IRON_CHESTPLATE)); - addCreativeItem(Item.get(Item.IRON_LEGGINGS)); - addCreativeItem(Item.get(Item.IRON_BOOTS)); - addCreativeItem(Item.get(Item.DIAMOND_HELMET)); - addCreativeItem(Item.get(Item.DIAMOND_CHESTPLATE)); - addCreativeItem(Item.get(Item.DIAMOND_LEGGINGS)); - addCreativeItem(Item.get(Item.DIAMOND_BOOTS)); - addCreativeItem(Item.get(Item.GOLD_HELMET)); - addCreativeItem(Item.get(Item.GOLD_CHESTPLATE)); - addCreativeItem(Item.get(Item.GOLD_LEGGINGS)); - addCreativeItem(Item.get(Item.GOLD_BOOTS)); - addCreativeItem(Item.get(Item.ELYTRA)); - addCreativeItem(Item.get(Item.LEVER)); - addCreativeItem(Item.get(Item.REDSTONE_LAMP)); - addCreativeItem(Item.get(Item.REDSTONE_TORCH)); - addCreativeItem(Item.get(Item.WOODEN_PRESSURE_PLATE)); - addCreativeItem(Item.get(Item.STONE_PRESSURE_PLATE)); - addCreativeItem(Item.get(Item.LIGHT_WEIGHTED_PRESSURE_PLATE)); - addCreativeItem(Item.get(Item.HEAVY_WEIGHTED_PRESSURE_PLATE)); - addCreativeItem(Item.get(Item.WOODEN_BUTTON, 5)); - addCreativeItem(Item.get(Item.STONE_BUTTON, 5)); - addCreativeItem(Item.get(Item.DAYLIGHT_DETECTOR)); - addCreativeItem(Item.get(Item.TRIPWIRE_HOOK)); - addCreativeItem(Item.get(Item.REPEATER)); - addCreativeItem(Item.get(Item.COMPARATOR)); - addCreativeItem(Item.get(Item.DISPENSER, 3)); - addCreativeItem(Item.get(Item.DROPPER)); - addCreativeItem(Item.get(Item.PISTON)); - addCreativeItem(Item.get(Item.STICKY_PISTON)); - addCreativeItem(Item.get(Item.OBSERVER)); - addCreativeItem(Item.get(Item.HOPPER)); - addCreativeItem(Item.get(Item.SNOWBALL)); - addCreativeItem(Item.get(Item.ENDER_PEARL)); - addCreativeItem(Item.get(Item.ENDER_EYE)); - - //Seeds - addCreativeItem(Item.get(Item.COAL, 0)); - addCreativeItem(Item.get(Item.COAL, 1)); - addCreativeItem(Item.get(Item.DIAMOND, 0)); - addCreativeItem(Item.get(Item.IRON_INGOT, 0)); - addCreativeItem(Item.get(Item.GOLD_INGOT, 0)); - addCreativeItem(Item.get(Item.EMERALD, 0)); - addCreativeItem(Item.get(Item.STICK, 0)); - addCreativeItem(Item.get(Item.BOWL, 0)); - addCreativeItem(Item.get(Item.STRING, 0)); - addCreativeItem(Item.get(Item.FEATHER, 0)); - addCreativeItem(Item.get(Item.FLINT, 0)); - addCreativeItem(Item.get(Item.LEATHER, 0)); - addCreativeItem(Item.get(Item.RABBIT_HIDE, 0)); - addCreativeItem(Item.get(Item.CLAY, 0)); - addCreativeItem(Item.get(Item.SUGAR, 0)); - addCreativeItem(Item.get(Item.BRICK, 0)); - addCreativeItem(Item.get(Item.NETHER_BRICK, 0)); - addCreativeItem(Item.get(Item.NETHER_QUARTZ, 0)); - addCreativeItem(Item.get(Item.PAPER, 0)); - addCreativeItem(Item.get(Item.BOOK, 0)); - addCreativeItem(Item.get(Item.ARROW, 0)); - addCreativeItem(Item.get(Item.BONE, 0)); - addCreativeItem(Item.get(Item.EMPTY_MAP, 0)); - addCreativeItem(Item.get(Item.SUGARCANE, 0)); - addCreativeItem(Item.get(Item.WHEAT, 0)); - addCreativeItem(Item.get(Item.SEEDS, 0)); - addCreativeItem(Item.get(Item.PUMPKIN_SEEDS, 0)); - addCreativeItem(Item.get(Item.MELON_SEEDS, 0)); - addCreativeItem(Item.get(Item.BEETROOT_SEEDS, 0)); - addCreativeItem(Item.get(Item.EGG, 0)); - addCreativeItem(Item.get(Item.APPLE, 0)); - addCreativeItem(Item.get(Item.GOLDEN_APPLE, 0)); - addCreativeItem(Item.get(Item.GOLDEN_APPLE_ENCHANTED, 0)); - addCreativeItem(Item.get(Item.RAW_FISH, 0)); - addCreativeItem(Item.get(Item.RAW_SALMON, 0)); - addCreativeItem(Item.get(Item.CLOWNFISH, 0)); - addCreativeItem(Item.get(Item.PUFFERFISH, 0)); - addCreativeItem(Item.get(Item.COOKED_FISH, 0)); - addCreativeItem(Item.get(Item.COOKED_SALMON, 0)); - addCreativeItem(Item.get(Item.ROTTEN_FLESH, 0)); - addCreativeItem(Item.get(Item.MUSHROOM_STEW, 0)); - addCreativeItem(Item.get(Item.BREAD, 0)); - addCreativeItem(Item.get(Item.RAW_PORKCHOP, 0)); - addCreativeItem(Item.get(Item.COOKED_PORKCHOP, 0)); - addCreativeItem(Item.get(Item.RAW_CHICKEN, 0)); - addCreativeItem(Item.get(Item.COOKED_CHICKEN, 0)); - addCreativeItem(Item.get(Item.RAW_MUTTON, 0)); - addCreativeItem(Item.get(Item.COOKED_MUTTON, 0)); - addCreativeItem(Item.get(Item.RAW_BEEF, 0)); - addCreativeItem(Item.get(Item.STEAK, 0)); - addCreativeItem(Item.get(Item.MELON, 0)); - addCreativeItem(Item.get(Item.CARROT, 0)); - addCreativeItem(Item.get(Item.POTATO, 0)); - addCreativeItem(Item.get(Item.BAKED_POTATO, 0)); - addCreativeItem(Item.get(Item.POISONOUS_POTATO, 0)); - addCreativeItem(Item.get(Item.BEETROOT, 0)); - addCreativeItem(Item.get(Item.COOKIE, 0)); - addCreativeItem(Item.get(Item.PUMPKIN_PIE, 0)); - addCreativeItem(Item.get(Item.RAW_RABBIT, 0)); - addCreativeItem(Item.get(Item.COOKED_RABBIT, 0)); - addCreativeItem(Item.get(Item.RABBIT_STEW, 0)); - addCreativeItem(Item.get(Item.CHORUS_FRUIT, 0)); - addCreativeItem(Item.get(Item.POPPED_CHORUS_FRUIT, 0)); - addCreativeItem(Item.get(Item.NETHER_STAR, 0)); - addCreativeItem(Item.get(Item.MAGMA_CREAM, 0)); - addCreativeItem(Item.get(Item.BLAZE_ROD, 0)); - addCreativeItem(Item.get(Item.GOLD_NUGGET, 0)); - addCreativeItem(Item.get(Item.GOLDEN_CARROT, 0)); - addCreativeItem(Item.get(Item.GLISTERING_MELON, 0)); - addCreativeItem(Item.get(Item.RABBIT_FOOT, 0)); - addCreativeItem(Item.get(Item.GHAST_TEAR, 0)); - addCreativeItem(Item.get(Item.SLIMEBALL, 0)); - addCreativeItem(Item.get(Item.BLAZE_POWDER, 0)); - addCreativeItem(Item.get(Item.NETHER_WART, 0)); - addCreativeItem(Item.get(Item.GUNPOWDER, 0)); - addCreativeItem(Item.get(Item.GLOWSTONE_DUST, 0)); - addCreativeItem(Item.get(Item.SPIDER_EYE, 0)); - addCreativeItem(Item.get(Item.FERMENTED_SPIDER_EYE, 0)); - addCreativeItem(Item.get(Item.DRAGON_BREATH)); - addCreativeItem(Item.get(Item.CARROT_ON_A_STICK)); - addCreativeItem(Item.get(Item.EXPERIENCE_BOTTLE)); - addCreativeItem(Item.get(Item.SHULKER_SHELL)); - addCreativeItem(Item.get(Item.PRISMARINE_SHARD, 0)); - addCreativeItem(Item.get(Item.PRISMARINE_CRYSTALS, 0)); - for (int color : dyeColors) { - addCreativeItem(Item.get(Item.DYE, color)); + for (Map map : list) { + try { + int id = (int) map.get("id"); + int damage = (int) map.getOrDefault("damage", 0); + String hex = (String) map.get("nbt_hex"); + byte[] nbt = hex != null ? DatatypeConverter.parseHexBinary(hex) : new byte[0]; + + addCreativeItem(Item.get(id, damage, 1, nbt)); + } catch (Exception e) { + MainLogger.getLogger().logException(e); + } } - - //Potion - addCreativeItem(Item.get(Item.GLASS_BOTTLE, 0)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.NO_EFFECTS)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.MUNDANE)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.MUNDANE_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.THICK)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.AWKWARD)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.NIGHT_VISION)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.NIGHT_VISION_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.INVISIBLE)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.INVISIBLE_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.LEAPING)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.LEAPING_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.LEAPING_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.FIRE_RESISTANCE)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.FIRE_RESISTANCE_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.SPEED)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.SPEED_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.SPEED_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.SLOWNESS)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.SLOWNESS_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.WATER_BREATHING)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.WATER_BREATHING_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.INSTANT_HEALTH)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.INSTANT_HEALTH_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.HARMING)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.HARMING_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.POISON)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.POISON_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.POISON_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.REGENERATION)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.REGENERATION_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.REGENERATION_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.STRENGTH)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.STRENGTH_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.STRENGTH_II)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.WEAKNESS)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.WEAKNESS_LONG)); - addCreativeItem(Item.get(Item.POTION, ItemPotion.DECAY)); - - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.NO_EFFECTS)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.MUNDANE)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.MUNDANE_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.THICK)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.AWKWARD)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.NIGHT_VISION)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.NIGHT_VISION_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.INVISIBLE)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.INVISIBLE_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.LEAPING)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.LEAPING_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.LEAPING_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.FIRE_RESISTANCE)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.FIRE_RESISTANCE_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.SPEED)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.SPEED_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.SPEED_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.SLOWNESS)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.SLOWNESS_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.WATER_BREATHING)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.WATER_BREATHING_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.INSTANT_HEALTH)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.INSTANT_HEALTH_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.HARMING)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.HARMING_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.POISON)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.POISON_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.POISON_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.REGENERATION)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.REGENERATION_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.REGENERATION_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.STRENGTH)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.STRENGTH_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.STRENGTH_II)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.WEAKNESS)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.WEAKNESS_LONG)); - addCreativeItem(Item.get(Item.SPLASH_POTION, ItemPotion.DECAY)); - - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.NO_EFFECTS)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.MUNDANE)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.MUNDANE_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.THICK)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.AWKWARD)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.NIGHT_VISION)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.NIGHT_VISION_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.INVISIBLE)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.INVISIBLE_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.LEAPING)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.LEAPING_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.LEAPING_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.FIRE_RESISTANCE)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.FIRE_RESISTANCE_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.SPEED)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.SPEED_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.SPEED_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.SLOWNESS)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.SLOWNESS_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.WATER_BREATHING)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.WATER_BREATHING_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.INSTANT_HEALTH)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.INSTANT_HEALTH_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.HARMING)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.HARMING_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.POISON)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.POISON_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.POISON_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.REGENERATION)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.REGENERATION_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.REGENERATION_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.STRENGTH)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.STRENGTH_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.STRENGTH_II)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.WEAKNESS)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.WEAKNESS_LONG)); - addCreativeItem(Item.get(Item.LINGERING_POTION, ItemPotion.DECAY)); } public static void clearCreativeItems() { @@ -1870,16 +1279,24 @@ public Tag getNamedTagEntry(String name) { public CompoundTag getNamedTag() { if (!this.hasCompoundTag()) { return null; - } else if (this.cachedNBT != null) { - return this.cachedNBT; } - return this.cachedNBT = parseCompoundTag(this.tags); + + if (this.cachedNBT == null) { + this.cachedNBT = parseCompoundTag(this.tags); + } + + if (this.cachedNBT != null) { + this.cachedNBT.setName(""); + } + + return this.cachedNBT; } public Item setNamedTag(CompoundTag tag) { if (tag.isEmpty()) { return this.clearNamedTag(); } + tag.setName(null); this.cachedNBT = tag; this.tags = writeCompoundTag(tag); @@ -1891,6 +1308,23 @@ public Item clearNamedTag() { return this.setCompoundTag(new byte[0]); } + public static CompoundTag parseCompoundTag(byte[] tag) { + try { + return NBTIO.read(tag, ByteOrder.LITTLE_ENDIAN); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + public byte[] writeCompoundTag(CompoundTag tag) { + try { + tag.setName(""); + return NBTIO.write(tag, ByteOrder.LITTLE_ENDIAN); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public int getCount() { return count; } @@ -1899,6 +1333,10 @@ public void setCount(int count) { this.count = count; } + public boolean isNull() { + return this.count <= 0 || this.id == AIR; + } + final public String getName() { return this.hasCustomName() ? this.getCustomName() : this.name; } @@ -2042,6 +1480,22 @@ public boolean onActivate(Level level, Player player, Block block, Block target, return false; } + /** + * Called when a player uses the item on air, for example throwing a projectile. + * Returns whether the item was changed, for example count decrease or durability change. + */ + public boolean onClickAir(Player player, Vector3 directionVector) { + return false; + } + + /** + * Called when a player is using this item and releases it. Used to handle bow shoot actions. + * Returns whether the item was changed, for example count decrease or durability change. + */ + public boolean onReleaseUsing(Player player) { + return false; + } + @Override public final boolean equals(Object item) { return item instanceof Item && this.equals((Item) item, true); @@ -2052,27 +1506,41 @@ public final boolean equals(Item item, boolean checkDamage) { } public final boolean equals(Item item, boolean checkDamage, boolean checkCompound) { - return this.getId() == item.getId() && (!checkDamage || this.getDamage() == item.getDamage()) && (!checkCompound || Arrays.equals(this.getCompoundTag(), item.getCompoundTag())); + if (this.getId() == item.getId() && (!checkDamage || this.getDamage() == item.getDamage())) { + if (checkCompound) { + if (Arrays.equals(this.getCompoundTag(), item.getCompoundTag())) { + return true; + } else if (this.hasCompoundTag() && item.hasCompoundTag()) { + return this.getNamedTag().equals(item.getNamedTag()); + } + } else { + return true; + } + } + + return false; + } + + /** + * Returns whether the specified item stack has the same ID, damage, NBT and count as this item stack. + */ + public final boolean equalsExact(Item other) { + return this.equals(other, true, true) && this.count == other.count; } + @Deprecated public final boolean deepEquals(Item item) { - return deepEquals(item, true); + return equals(item, true); } + @Deprecated public final boolean deepEquals(Item item, boolean checkDamage) { - return deepEquals(item, checkDamage, true); + return equals(item, checkDamage, true); } + @Deprecated public final boolean deepEquals(Item item, boolean checkDamage, boolean checkCompound) { - if (this.equals(item, checkDamage, checkCompound)) { - return true; - } else if (item.hasCompoundTag()) { - return item.getNamedTag().equals(this.getNamedTag()); - } else if (this.hasCompoundTag()) { - return this.getNamedTag().equals(item.getNamedTag()); - } - - return false; + return equals(item, checkDamage, checkCompound); } @Override diff --git a/src/main/java/cn/nukkit/item/ItemArmor.java b/src/main/java/cn/nukkit/item/ItemArmor.java index 618bc70d60..a292eb2cdc 100644 --- a/src/main/java/cn/nukkit/item/ItemArmor.java +++ b/src/main/java/cn/nukkit/item/ItemArmor.java @@ -1,5 +1,8 @@ package cn.nukkit.item; +import cn.nukkit.Player; +import cn.nukkit.math.Vector3; + /** * author: MagicDroidX * Nukkit Project @@ -38,6 +41,25 @@ public boolean isArmor() { return true; } + @Override + public boolean onClickAir(Player player, Vector3 directionVector) { + if (this.isHelmet() && player.getInventory().getHelmet().isNull()) { + if (player.getInventory().setHelmet(this)) + player.getInventory().clear(player.getInventory().getHeldItemIndex()); + } else if (this.isChestplate() && player.getInventory().getChestplate().isNull()) { + if (player.getInventory().setChestplate(this)) + player.getInventory().clear(player.getInventory().getHeldItemIndex()); + } else if (this.isLeggings() && player.getInventory().getLeggings().isNull()) { + if (player.getInventory().setHelmet(this)) + player.getInventory().clear(player.getInventory().getHeldItemIndex()); + } else if (this.isBoots() && player.getInventory().getBoots().isNull()) { + if (player.getInventory().setBoots(this)) + player.getInventory().clear(player.getInventory().getHeldItemIndex()); + } + + return this.getCount() == 0; + } + @Override public int getEnchantAbility() { switch (this.getTier()) { diff --git a/src/main/java/cn/nukkit/item/ItemBookWritten.java b/src/main/java/cn/nukkit/item/ItemBookWritten.java new file mode 100644 index 0000000000..f4d699b393 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemBookWritten.java @@ -0,0 +1,71 @@ +package cn.nukkit.item; + +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.nbt.tag.ListTag; + +import java.util.concurrent.ThreadLocalRandom; + +public class ItemBookWritten extends Item { + + protected boolean isWritten = false; + + public ItemBookWritten() { + this(0, 1); + } + + public ItemBookWritten(Integer meta, int count) { + super(Item.WRITTEN_BOOK, 0, count, "Book"); + } + + public Item writeBook(String author, String title, String[] pages) { + ListTag pageList = new ListTag<>("pages"); + for (String page : pages) { + pageList.add(new CompoundTag().putString("photoname", "").putString("text", page)); + } + return writeBook(author, title, pageList); + } + + public Item writeBook(String author, String title, ListTag pages) { + if (pages.size() > 50 || pages.size() <= 0) return this; //Minecraft does not support more than 50 pages + if (this.isWritten) return this; //Book content can only be updated once + CompoundTag tag; + if (!this.hasCompoundTag()) { + tag = new CompoundTag(); + } else { + tag = this.getNamedTag(); + } + + tag.putString("author", author); + tag.putString("title", title); + tag.putList(pages); + + tag.putInt("generation", 0); + long randomId = 1095216660480L + ThreadLocalRandom.current().nextLong(0L, 2147483647L); + tag.putLong("id", randomId); + + this.isWritten = true; + return this.setNamedTag(tag); + } + + public String getAuthor() { + if (!this.isWritten) return ""; + return this.getNamedTag().getString("author"); + } + + public String getTitle() { + if (!this.isWritten) return "Book"; + return this.getNamedTag().getString("title"); + } + + public String[] getPages() { + if (!this.isWritten) return new String[0]; + ListTag tag = (ListTag) this.getNamedTag().getList("pages"); + String[] pages = new String[tag.size()]; + int i = 0; + for (CompoundTag pageCompound : tag.getAll()) { + pages[i] = pageCompound.getString("text"); + i++; + } + return pages; + } +} \ No newline at end of file diff --git a/src/main/java/cn/nukkit/item/ItemBow.java b/src/main/java/cn/nukkit/item/ItemBow.java index ada68422ad..1a4e23dab1 100644 --- a/src/main/java/cn/nukkit/item/ItemBow.java +++ b/src/main/java/cn/nukkit/item/ItemBow.java @@ -1,5 +1,21 @@ package cn.nukkit.item; +import cn.nukkit.Player; +import cn.nukkit.Server; +import cn.nukkit.block.BlockAir; +import cn.nukkit.entity.projectile.EntityArrow; +import cn.nukkit.entity.projectile.EntityProjectile; +import cn.nukkit.event.entity.EntityShootBowEvent; +import cn.nukkit.event.entity.ProjectileLaunchEvent; +import cn.nukkit.item.enchantment.Enchantment; +import cn.nukkit.level.sound.LaunchSound; +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.nbt.tag.DoubleTag; +import cn.nukkit.nbt.tag.FloatTag; +import cn.nukkit.nbt.tag.ListTag; + +import java.util.Random; + /** * author: MagicDroidX * Nukkit Project @@ -27,4 +43,91 @@ public int getMaxDurability() { public int getEnchantAbility() { return 1; } + + public boolean onReleaseUsing(Player player) { + Item itemArrow = Item.get(Item.ARROW, 0, 1); + + if (player.isSurvival() && !player.getInventory().contains(itemArrow)) { + player.getInventory().sendContents(player); + return false; + } + + double damage = 2; + boolean flame = false; + + if (this.hasEnchantments()) { + Enchantment bowDamage = this.getEnchantment(Enchantment.ID_BOW_POWER); + + if (bowDamage != null && bowDamage.getLevel() > 0) { + damage += 0.25 * (bowDamage.getLevel() + 1); + } + + Enchantment flameEnchant = this.getEnchantment(Enchantment.ID_BOW_FLAME); + flame = flameEnchant != null && flameEnchant.getLevel() > 0; + } + + CompoundTag nbt = new CompoundTag() + .putList(new ListTag("Pos") + .add(new DoubleTag("", player.x)) + .add(new DoubleTag("", player.y + player.getEyeHeight())) + .add(new DoubleTag("", player.z))) + .putList(new ListTag("Motion") + .add(new DoubleTag("", -Math.sin(player.yaw / 180 * Math.PI) * Math.cos(player.pitch / 180 * Math.PI))) + .add(new DoubleTag("", -Math.sin(player.pitch / 180 * Math.PI))) + .add(new DoubleTag("", Math.cos(player.yaw / 180 * Math.PI) * Math.cos(player.pitch / 180 * Math.PI)))) + .putList(new ListTag("Rotation") + .add(new FloatTag("", (player.yaw > 180 ? 360 : 0) - (float) player.yaw)) + .add(new FloatTag("", (float) -player.pitch))) + .putShort("Fire", player.isOnFire() || flame ? 45 * 60 : 0) + .putDouble("damage", damage); + + int diff = (Server.getInstance().getTick() - player.getStartActionTick()); + double p = (double) diff / 20; + + double f = Math.min((p * p + p * 2) / 3, 1) * 2; + EntityShootBowEvent entityShootBowEvent = new EntityShootBowEvent(player, this, new EntityArrow(player.chunk, nbt, player, f == 2), f); + + if (f < 0.1 || diff < 5) { + entityShootBowEvent.setCancelled(); + } + + Server.getInstance().getPluginManager().callEvent(entityShootBowEvent); + if (entityShootBowEvent.isCancelled()) { + entityShootBowEvent.getProjectile().kill(); + player.getInventory().sendContents(player); + } else { + entityShootBowEvent.getProjectile().setMotion(entityShootBowEvent.getProjectile().getMotion().multiply(entityShootBowEvent.getForce())); + if (player.isSurvival()) { + Enchantment infinity; + + if (!this.hasEnchantments() || (infinity = this.getEnchantment(Enchantment.ID_BOW_INFINITY)) == null || infinity.getLevel() <= 0) + player.getInventory().removeItem(itemArrow); + if (!this.isUnbreakable()) { + Enchantment durability = this.getEnchantment(Enchantment.ID_DURABILITY); + if (!(durability != null && durability.getLevel() > 0 && (100 / (durability.getLevel() + 1)) <= new Random().nextInt(100))) { + this.setDamage(this.getDamage() + 1); + if (this.getDamage() >= 385) { + player.getInventory().setItemInHand(new ItemBlock(new BlockAir(), 0, 0)); + } else { + player.getInventory().setItemInHand(this); + } + } + } + } + if (entityShootBowEvent.getProjectile() instanceof EntityProjectile) { + ProjectileLaunchEvent projectev = new ProjectileLaunchEvent(entityShootBowEvent.getProjectile()); + Server.getInstance().getPluginManager().callEvent(projectev); + if (projectev.isCancelled()) { + entityShootBowEvent.getProjectile().kill(); + } else { + entityShootBowEvent.getProjectile().spawnToAll(); + player.level.addSound(new LaunchSound(player), player.getViewers().values()); + } + } else { + entityShootBowEvent.getProjectile().spawnToAll(); + } + } + + return true; + } } diff --git a/src/main/java/cn/nukkit/item/ItemEgg.java b/src/main/java/cn/nukkit/item/ItemEgg.java index 139071cf4f..38eb3f062f 100644 --- a/src/main/java/cn/nukkit/item/ItemEgg.java +++ b/src/main/java/cn/nukkit/item/ItemEgg.java @@ -4,7 +4,7 @@ * author: MagicDroidX * Nukkit Project */ -public class ItemEgg extends Item { +public class ItemEgg extends ProjectileItem { public ItemEgg() { this(0, 1); @@ -17,4 +17,14 @@ public ItemEgg(Integer meta) { public ItemEgg(Integer meta, int count) { super(EGG, meta, count, "Egg"); } + + @Override + public String getProjectileEntityType() { + return "Egg"; + } + + @Override + public float getThrowForce() { + return 1.5f; + } } diff --git a/src/main/java/cn/nukkit/item/ItemEnderPearl.java b/src/main/java/cn/nukkit/item/ItemEnderPearl.java index b2895fdd3a..138de386ae 100644 --- a/src/main/java/cn/nukkit/item/ItemEnderPearl.java +++ b/src/main/java/cn/nukkit/item/ItemEnderPearl.java @@ -1,6 +1,6 @@ package cn.nukkit.item; -public class ItemEnderPearl extends Item { +public class ItemEnderPearl extends ProjectileItem { public ItemEnderPearl() { this(0, 1); @@ -18,4 +18,14 @@ public ItemEnderPearl(Integer meta, int count) { public int getMaxStackSize() { return 16; } + + @Override + public String getProjectileEntityType() { + return "EnderPearl"; + } + + @Override + public float getThrowForce() { + return 1.5f; + } } diff --git a/src/main/java/cn/nukkit/item/ItemExpBottle.java b/src/main/java/cn/nukkit/item/ItemExpBottle.java index 04c288b5f4..247e282431 100644 --- a/src/main/java/cn/nukkit/item/ItemExpBottle.java +++ b/src/main/java/cn/nukkit/item/ItemExpBottle.java @@ -4,7 +4,7 @@ * Created on 2015/12/25 by xtypr. * Package cn.nukkit.item in project Nukkit . */ -public class ItemExpBottle extends Item { +public class ItemExpBottle extends ProjectileItem { public ItemExpBottle() { this(0, 1); @@ -18,4 +18,14 @@ public ItemExpBottle(Integer meta, int count) { super(EXPERIENCE_BOTTLE, meta, count, "Bottle o' Enchanting"); } + @Override + public String getProjectileEntityType() { + return "ThrownExpBottle"; + } + + @Override + public float getThrowForce() { + return 1f; + } + } diff --git a/src/main/java/cn/nukkit/item/ItemPotionSplash.java b/src/main/java/cn/nukkit/item/ItemPotionSplash.java index d337540f0c..fa4bcc38f6 100644 --- a/src/main/java/cn/nukkit/item/ItemPotionSplash.java +++ b/src/main/java/cn/nukkit/item/ItemPotionSplash.java @@ -1,10 +1,12 @@ package cn.nukkit.item; +import cn.nukkit.nbt.tag.CompoundTag; + /** * Created on 2015/12/27 by xtypr. * Package cn.nukkit.item in project Nukkit . */ -public class ItemPotionSplash extends Item { +public class ItemPotionSplash extends ProjectileItem { public ItemPotionSplash(Integer meta) { this(meta, 1); @@ -23,4 +25,19 @@ public int getMaxStackSize() { public boolean canBeActivated() { return true; } + + @Override + public String getProjectileEntityType() { + return "ThrownPotion"; + } + + @Override + public float getThrowForce() { + return 1f; + } + + @Override + protected void correctNBT(CompoundTag nbt) { + nbt.putInt("PotionId", this.meta); + } } diff --git a/src/main/java/cn/nukkit/item/ItemRecord.java b/src/main/java/cn/nukkit/item/ItemRecord.java new file mode 100644 index 0000000000..84f5c0fec1 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecord.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +/** + * @author CreeperFace + */ +public abstract class ItemRecord extends Item { + + public ItemRecord() { + this(0, 1); + } + + public ItemRecord(Integer meta) { + this(meta, 1); + } + + public ItemRecord(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getMaxStackSize() { + return 1; + } + + public abstract int getSoundId(); +} diff --git a/src/main/java/cn/nukkit/item/ItemRecord11.java b/src/main/java/cn/nukkit/item/ItemRecord11.java new file mode 100644 index 0000000000..a5117a0b2b --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecord11.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecord11 extends ItemRecord { + + public ItemRecord11() { + this(0, 1); + } + + public ItemRecord11(Integer meta) { + this(meta, 1); + } + + public ItemRecord11(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_11; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecord13.java b/src/main/java/cn/nukkit/item/ItemRecord13.java new file mode 100644 index 0000000000..5537802709 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecord13.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecord13 extends ItemRecord { + + public ItemRecord13() { + this(0, 1); + } + + public ItemRecord13(Integer meta) { + this(meta, 1); + } + + public ItemRecord13(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_13; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordBlocks.java b/src/main/java/cn/nukkit/item/ItemRecordBlocks.java new file mode 100644 index 0000000000..21aabbf583 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordBlocks.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordBlocks extends ItemRecord { + + public ItemRecordBlocks() { + this(0, 1); + } + + public ItemRecordBlocks(Integer meta) { + this(meta, 1); + } + + public ItemRecordBlocks(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_BLOCKS; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordCat.java b/src/main/java/cn/nukkit/item/ItemRecordCat.java new file mode 100644 index 0000000000..ac826f6853 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordCat.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordCat extends ItemRecord { + + public ItemRecordCat() { + this(0, 1); + } + + public ItemRecordCat(Integer meta) { + this(meta, 1); + } + + public ItemRecordCat(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_CAT; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordChirp.java b/src/main/java/cn/nukkit/item/ItemRecordChirp.java new file mode 100644 index 0000000000..3e8cc21ae0 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordChirp.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordChirp extends ItemRecord { + + public ItemRecordChirp() { + this(0, 1); + } + + public ItemRecordChirp(Integer meta) { + this(meta, 1); + } + + public ItemRecordChirp(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_CHIRP; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordFar.java b/src/main/java/cn/nukkit/item/ItemRecordFar.java new file mode 100644 index 0000000000..cd84d1def5 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordFar.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordFar extends ItemRecord { + + public ItemRecordFar() { + this(0, 1); + } + + public ItemRecordFar(Integer meta) { + this(meta, 1); + } + + public ItemRecordFar(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_FAR; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordMall.java b/src/main/java/cn/nukkit/item/ItemRecordMall.java new file mode 100644 index 0000000000..5c2da3936b --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordMall.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordMall extends ItemRecord { + + public ItemRecordMall() { + this(0, 1); + } + + public ItemRecordMall(Integer meta) { + this(meta, 1); + } + + public ItemRecordMall(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_MALL; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordMellohi.java b/src/main/java/cn/nukkit/item/ItemRecordMellohi.java new file mode 100644 index 0000000000..13fb5c2d11 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordMellohi.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordMellohi extends ItemRecord { + + public ItemRecordMellohi() { + this(0, 1); + } + + public ItemRecordMellohi(Integer meta) { + this(meta, 1); + } + + public ItemRecordMellohi(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_MELLOHI; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordStal.java b/src/main/java/cn/nukkit/item/ItemRecordStal.java new file mode 100644 index 0000000000..3a4824de7c --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordStal.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordStal extends ItemRecord { + + public ItemRecordStal() { + this(0, 1); + } + + public ItemRecordStal(Integer meta) { + this(meta, 1); + } + + public ItemRecordStal(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_STAL; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordStrad.java b/src/main/java/cn/nukkit/item/ItemRecordStrad.java new file mode 100644 index 0000000000..1c7e42dd8c --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordStrad.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordStrad extends ItemRecord { + + public ItemRecordStrad() { + this(0, 1); + } + + public ItemRecordStrad(Integer meta) { + this(meta, 1); + } + + public ItemRecordStrad(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_STRAD; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordWait.java b/src/main/java/cn/nukkit/item/ItemRecordWait.java new file mode 100644 index 0000000000..738f26f088 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordWait.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordWait extends ItemRecord { + + public ItemRecordWait() { + this(0, 1); + } + + public ItemRecordWait(Integer meta) { + this(meta, 1); + } + + public ItemRecordWait(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_WAIT; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemRecordWard.java b/src/main/java/cn/nukkit/item/ItemRecordWard.java new file mode 100644 index 0000000000..b8f2f79154 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ItemRecordWard.java @@ -0,0 +1,26 @@ +package cn.nukkit.item; + +import cn.nukkit.network.protocol.LevelSoundEventPacket; + +/** + * @author CreeperFace + */ +public class ItemRecordWard extends ItemRecord { + + public ItemRecordWard() { + this(0, 1); + } + + public ItemRecordWard(Integer meta) { + this(meta, 1); + } + + public ItemRecordWard(Integer meta, int count) { + super(meta, count); + } + + @Override + public int getSoundId() { + return LevelSoundEventPacket.SOUND_RECORD_WARD; + } +} diff --git a/src/main/java/cn/nukkit/item/ItemSnowball.java b/src/main/java/cn/nukkit/item/ItemSnowball.java index 47bf2dc6e5..ae6a5a2740 100644 --- a/src/main/java/cn/nukkit/item/ItemSnowball.java +++ b/src/main/java/cn/nukkit/item/ItemSnowball.java @@ -4,7 +4,7 @@ * author: MagicDroidX * Nukkit Project */ -public class ItemSnowball extends Item { +public class ItemSnowball extends ProjectileItem { public ItemSnowball() { this(0, 1); @@ -22,4 +22,14 @@ public ItemSnowball(Integer meta, int count) { public int getMaxStackSize() { return 16; } + + @Override + public String getProjectileEntityType() { + return "Snowball"; + } + + @Override + public float getThrowForce() { + return 1.5f; + } } diff --git a/src/main/java/cn/nukkit/item/ProjectileItem.java b/src/main/java/cn/nukkit/item/ProjectileItem.java new file mode 100644 index 0000000000..0ae17e87a0 --- /dev/null +++ b/src/main/java/cn/nukkit/item/ProjectileItem.java @@ -0,0 +1,70 @@ +package cn.nukkit.item; + +import cn.nukkit.Player; +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.projectile.EntityProjectile; +import cn.nukkit.event.entity.ProjectileLaunchEvent; +import cn.nukkit.level.sound.LaunchSound; +import cn.nukkit.math.Vector3; +import cn.nukkit.nbt.tag.CompoundTag; +import cn.nukkit.nbt.tag.DoubleTag; +import cn.nukkit.nbt.tag.FloatTag; +import cn.nukkit.nbt.tag.ListTag; + +/** + * @author CreeperFace + */ +public abstract class ProjectileItem extends Item { + + public ProjectileItem(int id, Integer meta, int count, String name) { + super(id, meta, count, name); + } + + abstract public String getProjectileEntityType(); + + abstract public float getThrowForce(); + + public boolean onClickAir(Player player, Vector3 directionVector) { + CompoundTag nbt = new CompoundTag() + .putList(new ListTag("Pos") + .add(new DoubleTag("", player.x)) + .add(new DoubleTag("", player.y + player.getEyeHeight())) + .add(new DoubleTag("", player.z))) + .putList(new ListTag("Motion") + .add(new DoubleTag("", directionVector.x)) + .add(new DoubleTag("", directionVector.y)) + .add(new DoubleTag("", directionVector.z))) + .putList(new ListTag("Rotation") + .add(new FloatTag("", (float) player.yaw)) + .add(new FloatTag("", (float) player.pitch))); + + this.correctNBT(nbt); + + Entity projectile = Entity.createEntity(this.getProjectileEntityType(), player.getLevel().getChunk(player.getFloorX() >> 4, player.getFloorZ() >> 4), nbt, player); + if (projectile != null) { + projectile.setMotion(projectile.getMotion().multiply(this.getThrowForce())); + this.count--; + + if (projectile instanceof EntityProjectile) { + ProjectileLaunchEvent ev = new ProjectileLaunchEvent((EntityProjectile) projectile); + + player.getServer().getPluginManager().callEvent(ev); + if (ev.isCancelled()) { + projectile.kill(); + } else { + projectile.spawnToAll(); + player.getLevel().addSound(new LaunchSound(player), player.getViewers().values()); + } + } else { + projectile.spawnToAll(); + } + } else { + return false; + } + return true; + } + + protected void correctNBT(CompoundTag nbt) { + + } +} diff --git a/src/main/java/cn/nukkit/item/enchantment/Enchantment.java b/src/main/java/cn/nukkit/item/enchantment/Enchantment.java index 77bffba444..78ae5c1e5d 100644 --- a/src/main/java/cn/nukkit/item/enchantment/Enchantment.java +++ b/src/main/java/cn/nukkit/item/enchantment/Enchantment.java @@ -90,7 +90,7 @@ public static Enchantment get(int id) { } public static Enchantment getEnchantment(int id) { - return get(id) == null ? null : get(id).clone(); + return get(id).clone(); } public static Enchantment[] getEnchantments() { diff --git a/src/main/java/cn/nukkit/level/GameRules.java b/src/main/java/cn/nukkit/level/GameRules.java index 5a6da6fb1a..466440a003 100644 --- a/src/main/java/cn/nukkit/level/GameRules.java +++ b/src/main/java/cn/nukkit/level/GameRules.java @@ -31,6 +31,7 @@ public GameRules() { this.addGameRule("spectatorsGenerateChunks", "true", ValueType.BOOLEAN_VALUE); this.addGameRule("spawnRadius", "10", ValueType.NUMERICAL_VALUE); this.addGameRule("disableElytraMovementCheck", "false", ValueType.BOOLEAN_VALUE); + this.addGameRule("pvp", "true", ValueType.BOOLEAN_VALUE); } public void addGameRule(String key, String value, ValueType type) { diff --git a/src/main/java/cn/nukkit/level/Level.java b/src/main/java/cn/nukkit/level/Level.java index 2952bb29f6..19ac2d6885 100644 --- a/src/main/java/cn/nukkit/level/Level.java +++ b/src/main/java/cn/nukkit/level/Level.java @@ -489,11 +489,11 @@ public void addSound(Sound sound, Collection players) { this.addSound(sound, players.stream().toArray(Player[]::new)); } - public void addLevelSoundEvent(byte type, int pitch, int data, Vector3 pos, boolean unknown, boolean disableRelativeVolume) { - this.addLevelSoundEvent(type, pitch, data, pos, this.players.values(), unknown, disableRelativeVolume); + public void addLevelSoundEvent(int type, int pitch, int data, Vector3 pos) { + this.addLevelSoundEvent(type, pitch, data, pos, false); } - public void addLevelSoundEvent(byte type, int pitch, int data, Vector3 pos, Collection players, boolean unknown, boolean disableRelativeVolume) { + public void addLevelSoundEvent(int type, int pitch, int data, Vector3 pos, boolean isGlobal) { LevelSoundEventPacket pk = new LevelSoundEventPacket(); pk.sound = type; pk.pitch = pitch; @@ -501,14 +501,9 @@ public void addLevelSoundEvent(byte type, int pitch, int data, Vector3 pos, Coll pk.x = (float) pos.x; pk.y = (float) pos.y; pk.z = (float) pos.z; - pk.unknownBool = unknown; - pk.disableRelativeVolume = disableRelativeVolume; + pk.isGlobal = isGlobal; - if (players == null) { - this.addChunkPacket(pos.getFloorX(), pos.getFloorZ(), pk); - } else { - Server.broadcastPacket(players, pk); - } + this.addChunkPacket(pos.getFloorX() >> 4, pos.getFloorZ() >> 4, pk); } public void addParticle(Particle particle) { @@ -676,30 +671,21 @@ public void checkTime() { } } - public void sendTime(Player player) { - if (this.stopTime) { + public void sendTime(Player... players) { + /*if (this.stopTime) { //TODO SetTimePacket pk0 = new SetTimePacket(); pk0.time = (int) this.time; player.dataPacket(pk0); - } + }*/ SetTimePacket pk = new SetTimePacket(); pk.time = (int) this.time; - player.dataPacket(pk); + Server.broadcastPacket(players, pk); } public void sendTime() { - if (this.stopTime) { - SetTimePacket pk0 = new SetTimePacket(); - pk0.time = (int) this.time; - Server.broadcastPacket(this.players.values().stream().toArray(Player[]::new), pk0); - } - - SetTimePacket pk = new SetTimePacket(); - pk.time = (int) this.time; - - Server.broadcastPacket(this.players.values().stream().toArray(Player[]::new), pk); + sendTime(this.players.values().stream().toArray(Player[]::new)); } public GameRules getGameRules() { @@ -767,8 +753,8 @@ public void doTick(int currentTick) { bolt.setEffect(false); } - this.addLevelSoundEvent(LevelSoundEventPacket.SOUND_THUNDER, 93, -1, vector, false, false); - this.addLevelSoundEvent(LevelSoundEventPacket.SOUND_EXPLODE, 93, -1, vector, false, false); + this.addLevelSoundEvent(LevelSoundEventPacket.SOUND_THUNDER, 93, -1, vector, false); + this.addLevelSoundEvent(LevelSoundEventPacket.SOUND_EXPLODE, 93, -1, vector, false); } } @@ -1809,6 +1795,7 @@ public Item useBreakOn(Vector3 vector, Item item, Player player, boolean createP BlockBreakEvent ev = new BlockBreakEvent(player, target, item, player.isCreative(), (player.lastBreak + breakTime * 1000) > System.currentTimeMillis()); + double distance; if (player.isSurvival() && !target.isBreakable(item)) { ev.setCancelled(); @@ -1955,6 +1942,7 @@ public Item useItemOn(Vector3 vector, Item item, BlockFace face, float fx, float return this.useItemOn(vector, item, face, fx, fy, fz, player, false); } + public Item useItemOn(Vector3 vector, Item item, BlockFace face, float fx, float fy, float fz, Player player, boolean playSound) { Block target = this.getBlock(vector); Block block = target.getSide(face); @@ -2001,6 +1989,7 @@ public Item useItemOn(Vector3 vector, Item item, BlockFace face, float fx, float } else { return null; } + } else if (target.canBeActivated() && target.onActivate(item, null)) { return item; } @@ -2096,7 +2085,7 @@ public Item useItemOn(Vector3 vector, Item item, BlockFace face, float fx, float } if (playSound) { - this.addSound(new BlockPlaceSound(hand, hand.getId())); + this.addLevelSoundEvent(LevelSoundEventPacket.SOUND_PLACE, 1, item.getId(), hand, false); } if (item.getCount() <= 0) { diff --git a/src/main/java/cn/nukkit/level/format/anvil/ChunkRequestTask.java b/src/main/java/cn/nukkit/level/format/anvil/ChunkRequestTask.java index 299d12db02..b4f9c55d9f 100644 --- a/src/main/java/cn/nukkit/level/format/anvil/ChunkRequestTask.java +++ b/src/main/java/cn/nukkit/level/format/anvil/ChunkRequestTask.java @@ -72,8 +72,6 @@ public void onRun() { for (int z = 0; z < 16; ++z) { orderedIds.put(this.getColumn(ids, x, z)); orderedData.put(this.getHalfColumn(meta, x, z)); - orderedSkyLight.put(this.getHalfColumn(skyLight, x, z)); - orderedLight.put(this.getHalfColumn(blockLight, x, z)); } } @@ -90,8 +88,6 @@ public void onRun() { buffer .put(orderedIds) .put(orderedData) - .put(orderedSkyLight) - .put(orderedLight) .put(orderedHeightMap) .put(orderedBiomeColors) .put(this.blockEntities) diff --git a/src/main/java/cn/nukkit/level/format/anvil/ChunkSection.java b/src/main/java/cn/nukkit/level/format/anvil/ChunkSection.java index 01df616960..5c290cad7e 100644 --- a/src/main/java/cn/nukkit/level/format/anvil/ChunkSection.java +++ b/src/main/java/cn/nukkit/level/format/anvil/ChunkSection.java @@ -251,11 +251,9 @@ public boolean isEmpty() { @Override public byte[] getBytes() { - ByteBuffer buffer = ByteBuffer.allocate(10240); + ByteBuffer buffer = ByteBuffer.allocate(6144); byte[] blocks = new byte[4096]; byte[] data = new byte[2048]; - byte[] skyLight = new byte[2048]; - byte[] blockLight = new byte[2048]; for (int x = 0; x < 16; x++) { for (int z = 0; z < 16; z++) { int i = (x << 7) | (z << 3); @@ -265,20 +263,12 @@ public byte[] getBytes() { int b1 = this.getBlockData(x, y, z); int b2 = this.getBlockData(x, y + 1, z); data[i | (y >> 1)] = (byte) ((b2 << 4) | b1); - b1 = this.getBlockSkyLight(x, y, z); - b2 = this.getBlockSkyLight(x, y + 1, z); - skyLight[i | (y >> 1)] = (byte) ((b2 << 4) | b1); - b1 = this.getBlockLight(x, y, z); - b2 = this.getBlockLight(x, y + 1, z); - blockLight[i | (y >> 1)] = (byte) ((b2 << 4) | b1); } } } return buffer .put(blocks) .put(data) - .put(skyLight) - .put(blockLight) .array(); } diff --git a/src/main/java/cn/nukkit/level/format/generic/EmptyChunkSection.java b/src/main/java/cn/nukkit/level/format/generic/EmptyChunkSection.java index b60a808572..c8be638548 100644 --- a/src/main/java/cn/nukkit/level/format/generic/EmptyChunkSection.java +++ b/src/main/java/cn/nukkit/level/format/generic/EmptyChunkSection.java @@ -3,7 +3,6 @@ import cn.nukkit.level.format.ChunkSection; import cn.nukkit.utils.ChunkException; -import java.nio.ByteBuffer; import java.util.Arrays; /** @@ -131,13 +130,7 @@ public boolean isEmpty() { @Override public byte[] getBytes() { - ByteBuffer buffer = ByteBuffer.allocate(10240); - byte[] skyLight = new byte[2048]; - Arrays.fill(skyLight, (byte) 0xff); - buffer.position(6144); - return buffer - .put(skyLight) - .array(); + return new byte[6144]; } @Override diff --git a/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java b/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java index a3e0c50e53..dce975c0fe 100644 --- a/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java +++ b/src/main/java/cn/nukkit/level/format/leveldb/LevelDB.java @@ -3,8 +3,8 @@ import cn.nukkit.Server; import cn.nukkit.blockentity.BlockEntity; import cn.nukkit.blockentity.BlockEntitySpawnable; -import cn.nukkit.level.Level; import cn.nukkit.level.GameRules; +import cn.nukkit.level.Level; import cn.nukkit.level.format.ChunkSection; import cn.nukkit.level.format.FullChunk; import cn.nukkit.level.format.LevelProvider; @@ -507,7 +507,7 @@ public void setSpawn(Vector3 pos) { this.levelData.putInt("SpawnY", (int) pos.y); this.levelData.putInt("SpawnZ", (int) pos.z); } - + @Override public GameRules getGamerules() { GameRules rules = new GameRules(); diff --git a/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java b/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java index dc1688b019..9e5566f414 100644 --- a/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java +++ b/src/main/java/cn/nukkit/level/particle/FloatingTextParticle.java @@ -2,13 +2,14 @@ import cn.nukkit.entity.Entity; import cn.nukkit.entity.data.EntityMetadata; -import cn.nukkit.entity.item.EntityItem; +import cn.nukkit.item.Item; import cn.nukkit.math.Vector3; -import cn.nukkit.network.protocol.AddEntityPacket; +import cn.nukkit.network.protocol.AddPlayerPacket; import cn.nukkit.network.protocol.DataPacket; import cn.nukkit.network.protocol.RemoveEntityPacket; import java.util.ArrayList; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; /** @@ -16,6 +17,8 @@ * Package cn.nukkit.level.particle in project Nukkit . */ public class FloatingTextParticle extends Particle { + + protected String text; protected String title; protected long entityId = -1; @@ -32,10 +35,18 @@ public FloatingTextParticle(Vector3 pos, String text, String title) { this.title = title; } + public String getText() { + return text; + } + public void setText(String text) { this.text = text; } + public String getTitle() { + return title; + } + public void setTitle(String title) { this.title = title; } @@ -66,10 +77,11 @@ public DataPacket[] encode() { } if (!this.invisible) { - AddEntityPacket pk = new AddEntityPacket(); + AddPlayerPacket pk = new AddPlayerPacket(); + pk.uuid = UUID.randomUUID(); + pk.username = ""; pk.entityUniqueId = this.entityId; pk.entityRuntimeId = this.entityId; - pk.type = EntityItem.NETWORK_ID; pk.x = (float) this.x; pk.y = (float) (this.y - 0.75); pk.z = (float) this.z; @@ -80,15 +92,18 @@ public DataPacket[] encode() { pk.pitch = 0; long flags = ( (1L << Entity.DATA_FLAG_CAN_SHOW_NAMETAG) | - (1L << Entity.DATA_FLAG_ALWAYS_SHOW_NAMETAG) | - (1L << Entity.DATA_FLAG_IMMOBILE) + (1L << Entity.DATA_FLAG_ALWAYS_SHOW_NAMETAG) | + (1L << Entity.DATA_FLAG_IMMOBILE) ); pk.metadata = new EntityMetadata() .putLong(Entity.DATA_FLAGS, flags) - .putString(Entity.DATA_NAMETAG, this.title + (!this.text.isEmpty() ? "\n" + this.text : "")); + .putString(Entity.DATA_NAMETAG, this.title + (!this.text.isEmpty() ? "\n" + this.text : "")) + .putLong(Entity.DATA_LEAD_HOLDER_EID,-1) + .putFloat(Entity.DATA_SCALE, 0.01f); //zero causes problems on debug builds? + pk.item = Item.get(Item.AIR); packets.add(pk); } return packets.stream().toArray(DataPacket[]::new); } -} +} \ No newline at end of file diff --git a/src/main/java/cn/nukkit/level/sound/LevelSoundEventSound.java b/src/main/java/cn/nukkit/level/sound/LevelSoundEventSound.java index 8d89a8c3b5..380c32b517 100644 --- a/src/main/java/cn/nukkit/level/sound/LevelSoundEventSound.java +++ b/src/main/java/cn/nukkit/level/sound/LevelSoundEventSound.java @@ -8,19 +8,19 @@ * @author Tee7even */ public class LevelSoundEventSound extends Sound { - protected final byte type; + protected final int type; protected int extraData; protected int pitch; - public LevelSoundEventSound(Vector3 pos, byte type) { + public LevelSoundEventSound(Vector3 pos, int type) { this(pos, type, -1, -1); } - public LevelSoundEventSound(Vector3 pos, byte type, int extraData) { + public LevelSoundEventSound(Vector3 pos, int type, int extraData) { this(pos, type, extraData, -1); } - public LevelSoundEventSound(Vector3 pos, byte type, int extraData, int pitch) { + public LevelSoundEventSound(Vector3 pos, int type, int extraData, int pitch) { super(pos.x, pos.y, pos.z); this.type = type; this.extraData = extraData; diff --git a/src/main/java/cn/nukkit/math/Angle.java b/src/main/java/cn/nukkit/math/Angle.java index 3b3c781f1f..549284a74a 100644 --- a/src/main/java/cn/nukkit/math/Angle.java +++ b/src/main/java/cn/nukkit/math/Angle.java @@ -2,7 +2,7 @@ import java.util.Locale; -import static java.lang.Math.*; +import static java.lang.Math.PI; /** * Copyright 2017 lmlstarqaq @@ -10,143 +10,143 @@ */ public final class Angle implements Comparable { - public static Angle fromDegree(float floatDegree) { - return new Angle(floatDegree, true); - } - - public static Angle fromDegree(double doubleDegree) { - return new Angle(doubleDegree, true); - } - - public static Angle fromRadian(float floatRadian) { - return new Angle(floatRadian, false); - } - - public static Angle fromRadian(double doubleRadian) { - return new Angle(doubleRadian, false); - } - - public static Angle asin(double v) { - return fromRadian(Math.asin(v)); - } - - public static Angle acos(double v) { - return fromRadian(Math.acos(v)); - } - - public static Angle atan(double v) { - return fromRadian(Math.atan(v)); - } - - public double sin() { - return Math.sin(asDoubleRadian()); - } - - public double cos() { - return Math.cos(asDoubleRadian()); - } - - public double tan() { - return Math.tan(asDoubleRadian()); - } - - public float asFloatRadian() { - if (isOriginDouble) { - if (isDegree) return (float) (doubleValue * PI / 180.0); - else return (float) doubleValue; - } else { - if (isDegree) return floatValue * (float) PI / 180.0f; - else return floatValue; - } - } - - public double asDoubleRadian() { - if (isOriginDouble) { - if (isDegree) return doubleValue * PI / 180.0; - else return doubleValue; - } else { - if (isDegree) return floatValue * PI / 180.0; - else return floatValue; - } - } - - public float asFloatDegree() { - if (isOriginDouble) { - if (isDegree) return (float) doubleValue; - else return (float) (doubleValue * 180.0 / PI); - } else { - if (isDegree) return floatValue; - else return floatValue * 180.0f / (float) PI; - } - } - - public double asDoubleDegree() { - if (isOriginDouble) { - if (isDegree) return doubleValue; - else return doubleValue * 180.0 / PI; - } else { - if (isDegree) return floatValue ; - else return floatValue * 180.0 / PI; - } - } - - public static int compare(Angle a, Angle b) { - return a.compareTo(b); - } + public static Angle fromDegree(float floatDegree) { + return new Angle(floatDegree, true); + } + + public static Angle fromDegree(double doubleDegree) { + return new Angle(doubleDegree, true); + } + + public static Angle fromRadian(float floatRadian) { + return new Angle(floatRadian, false); + } + + public static Angle fromRadian(double doubleRadian) { + return new Angle(doubleRadian, false); + } + + public static Angle asin(double v) { + return fromRadian(Math.asin(v)); + } + + public static Angle acos(double v) { + return fromRadian(Math.acos(v)); + } + + public static Angle atan(double v) { + return fromRadian(Math.atan(v)); + } + + public double sin() { + return Math.sin(asDoubleRadian()); + } + + public double cos() { + return Math.cos(asDoubleRadian()); + } + + public double tan() { + return Math.tan(asDoubleRadian()); + } + + public float asFloatRadian() { + if (isOriginDouble) { + if (isDegree) return (float) (doubleValue * PI / 180.0); + else return (float) doubleValue; + } else { + if (isDegree) return floatValue * (float) PI / 180.0f; + else return floatValue; + } + } + + public double asDoubleRadian() { + if (isOriginDouble) { + if (isDegree) return doubleValue * PI / 180.0; + else return doubleValue; + } else { + if (isDegree) return floatValue * PI / 180.0; + else return floatValue; + } + } + + public float asFloatDegree() { + if (isOriginDouble) { + if (isDegree) return (float) doubleValue; + else return (float) (doubleValue * 180.0 / PI); + } else { + if (isDegree) return floatValue; + else return floatValue * 180.0f / (float) PI; + } + } + + public double asDoubleDegree() { + if (isOriginDouble) { + if (isDegree) return doubleValue; + else return doubleValue * 180.0 / PI; + } else { + if (isDegree) return floatValue; + else return floatValue * 180.0 / PI; + } + } + + public static int compare(Angle a, Angle b) { + return a.compareTo(b); + } /* -- Override -- */ - @Override - public String toString() { - return String.format(Locale.ROOT, - "Angle[%s, %f%s = %f%s] [%d]", - isOriginDouble ? "Double" : "Float", - isOriginDouble ? doubleValue : floatValue, - isDegree ? "deg" : "rad", - isDegree ? (isOriginDouble ? asDoubleRadian() : asFloatRadian()) : - (isOriginDouble ? asDoubleDegree() : asFloatDegree()) , - isDegree ? "rad" : "deg", - hashCode() - ); - } - - @Override - public int compareTo(Angle o) { - return Double.compare(asDoubleRadian(), o.asDoubleRadian()); - } - - @Override - public boolean equals(Object obj) { - return obj instanceof Angle && this.compareTo((Angle) obj) == 0; - } - - @Override - public int hashCode() { - int hash; - if (isOriginDouble) hash = Double.hashCode(doubleValue); - else hash = Float.hashCode(floatValue); - if (isDegree) hash = hash ^ 0xABCD1234; - return hash; - } + @Override + public String toString() { + return String.format(Locale.ROOT, + "Angle[%s, %f%s = %f%s] [%d]", + isOriginDouble ? "Double" : "Float", + isOriginDouble ? doubleValue : floatValue, + isDegree ? "deg" : "rad", + isDegree ? (isOriginDouble ? asDoubleRadian() : asFloatRadian()) : + (isOriginDouble ? asDoubleDegree() : asFloatDegree()), + isDegree ? "rad" : "deg", + hashCode() + ); + } + + @Override + public int compareTo(Angle o) { + return Double.compare(asDoubleRadian(), o.asDoubleRadian()); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Angle && this.compareTo((Angle) obj) == 0; + } + + @Override + public int hashCode() { + int hash; + if (isOriginDouble) hash = Double.hashCode(doubleValue); + else hash = Float.hashCode(floatValue); + if (isDegree) hash = hash ^ 0xABCD1234; + return hash; + } /* -- Internal Part -- */ - private final float floatValue; - private final double doubleValue; - private final boolean isDegree, isOriginDouble; - - private Angle(float floatValue, boolean isDegree) { - this.isOriginDouble = false; - this.floatValue = floatValue; - this.doubleValue = 0.0; - this.isDegree = isDegree; - } - - private Angle(double doubleValue, boolean isDegree) { - this.isOriginDouble = true; - this.floatValue = 0.0f; - this.doubleValue = doubleValue; - this.isDegree = isDegree; - } + private final float floatValue; + private final double doubleValue; + private final boolean isDegree, isOriginDouble; + + private Angle(float floatValue, boolean isDegree) { + this.isOriginDouble = false; + this.floatValue = floatValue; + this.doubleValue = 0.0; + this.isDegree = isDegree; + } + + private Angle(double doubleValue, boolean isDegree) { + this.isOriginDouble = true; + this.floatValue = 0.0f; + this.doubleValue = doubleValue; + this.isDegree = isDegree; + } } diff --git a/src/main/java/cn/nukkit/math/BlockVector3.java b/src/main/java/cn/nukkit/math/BlockVector3.java index 379dd35c29..98d2d4544b 100644 --- a/src/main/java/cn/nukkit/math/BlockVector3.java +++ b/src/main/java/cn/nukkit/math/BlockVector3.java @@ -216,4 +216,12 @@ public BlockVector3 clone() { return null; } } + + public Vector3 asVector3() { + return new Vector3(this.x, this.y, this.z); + } + + public Vector3f asVector3f() { + return new Vector3f(this.x, this.y, this.z); + } } diff --git a/src/main/java/cn/nukkit/math/NukkitMath.java b/src/main/java/cn/nukkit/math/NukkitMath.java index 32368a2ca7..1858b57937 100644 --- a/src/main/java/cn/nukkit/math/NukkitMath.java +++ b/src/main/java/cn/nukkit/math/NukkitMath.java @@ -45,7 +45,7 @@ public static double round(double d) { public static double round(double d, int precision) { return ((double) Math.round(d * Math.pow(10, precision))) / Math.pow(10, precision); } - + public static double clamp(double check, double min, double max) { return check > max ? max : (check < min ? min : check); } diff --git a/src/main/java/cn/nukkit/math/Vector3.java b/src/main/java/cn/nukkit/math/Vector3.java index e80a3ddbcd..75c7695e6f 100644 --- a/src/main/java/cn/nukkit/math/Vector3.java +++ b/src/main/java/cn/nukkit/math/Vector3.java @@ -346,4 +346,12 @@ public Vector3 clone() { return null; } } + + public Vector3f asVector3f() { + return new Vector3f((float) this.x, (float) this.y, (float) this.z); + } + + public BlockVector3 asBlockVector3() { + return new BlockVector3(this.getFloorX(), this.getFloorY(), this.getFloorZ()); + } } diff --git a/src/main/java/cn/nukkit/math/Vector3f.java b/src/main/java/cn/nukkit/math/Vector3f.java index 3f1eba2461..d77200a278 100644 --- a/src/main/java/cn/nukkit/math/Vector3f.java +++ b/src/main/java/cn/nukkit/math/Vector3f.java @@ -324,4 +324,12 @@ public Vector3f clone() { return null; } } + + public Vector3 asVector3() { + return new Vector3(this.x, this.y, this.z); + } + + public BlockVector3 asBlockVector3() { + return new BlockVector3(getFloorX(), getFloorY(), getFloorZ()); + } } \ No newline at end of file diff --git a/src/main/java/cn/nukkit/network/Network.java b/src/main/java/cn/nukkit/network/Network.java index 72035a0d6e..73506daa9a 100644 --- a/src/main/java/cn/nukkit/network/Network.java +++ b/src/main/java/cn/nukkit/network/Network.java @@ -41,6 +41,7 @@ public class Network { private double download = 0; private String name; + private String subName; public Network(Server server) { this.registerPackets(); @@ -91,7 +92,7 @@ public void registerInterface(SourceInterface interfaz) { this.advancedInterfaces.add((AdvancedSourceInterface) interfaz); ((AdvancedSourceInterface) interfaz).setNetwork(this); } - interfaz.setName(this.name); + interfaz.setName(this.name + "!@#" + this.subName); } public void unregisterInterface(SourceInterface interfaz) { @@ -108,9 +109,17 @@ public String getName() { return name; } + public String getSubName() { + return subName; + } + + public void setSubName(String subName) { + this.subName = subName; + } + public void updateName() { for (SourceInterface interfaz : this.interfaces) { - interfaz.setName(this.name); + interfaz.setName(this.name + "!@#" + this.subName); } } @@ -140,7 +149,7 @@ public void processBatch(BatchPacket packet, Player player) { DataPacket pk; if ((pk = this.getPacket(buf[0])) != null) { - pk.setBuffer(buf, 1); + pk.setBuffer(buf, 3); //skip 2 more bytes pk.decode(); @@ -166,20 +175,7 @@ public void processBatch(BatchPacket packet, Player player) { */ public void processPackets(Player player, List packets) { if (packets.isEmpty()) return; - List filter = new ArrayList<>(); - for (DataPacket packet : packets) { - switch (packet.pid()) { - case ProtocolInfo.USE_ITEM_PACKET: - // Prevent double fire of PlayerInteractEvent - if (!filter.contains(ProtocolInfo.USE_ITEM_PACKET)) { - player.handleDataPacket(packet); - filter.add(ProtocolInfo.USE_ITEM_PACKET); - } - break; - default: - player.handleDataPacket(packet); - } - } + packets.forEach(player::handleDataPacket); } @@ -221,9 +217,7 @@ private void registerPackets() { this.packetPool = new Class[256]; this.registerPacket(ProtocolInfo.ADD_ENTITY_PACKET, AddEntityPacket.class); - this.registerPacket(ProtocolInfo.ADD_HANGING_ENTITY_PACKET, AddHangingEntityPacket.class); this.registerPacket(ProtocolInfo.ADD_ITEM_ENTITY_PACKET, AddItemEntityPacket.class); - this.registerPacket(ProtocolInfo.ADD_ITEM_PACKET, AddItemPacket.class); this.registerPacket(ProtocolInfo.ADD_PAINTING_PACKET, AddPaintingPacket.class); this.registerPacket(ProtocolInfo.ADD_PLAYER_PACKET, AddPlayerPacket.class); this.registerPacket(ProtocolInfo.ADVENTURE_SETTINGS_PACKET, AdventureSettingsPacket.class); @@ -237,16 +231,13 @@ private void registerPackets() { this.registerPacket(ProtocolInfo.CHANGE_DIMENSION_PACKET, ChangeDimensionPacket.class); this.registerPacket(ProtocolInfo.CHUNK_RADIUS_UPDATED_PACKET, ChunkRadiusUpdatedPacket.class); this.registerPacket(ProtocolInfo.CLIENTBOUND_MAP_ITEM_DATA_PACKET, ClientboundMapItemDataPacket.class); - this.registerPacket(ProtocolInfo.COMMAND_STEP_PACKET, CommandStepPacket.class); + this.registerPacket(ProtocolInfo.COMMAND_REQUEST_PACKET, CommandRequestPacket.class); this.registerPacket(ProtocolInfo.CONTAINER_CLOSE_PACKET, ContainerClosePacket.class); this.registerPacket(ProtocolInfo.CONTAINER_OPEN_PACKET, ContainerOpenPacket.class); - this.registerPacket(ProtocolInfo.CONTAINER_SET_CONTENT_PACKET, ContainerSetContentPacket.class); this.registerPacket(ProtocolInfo.CONTAINER_SET_DATA_PACKET, ContainerSetDataPacket.class); - this.registerPacket(ProtocolInfo.CONTAINER_SET_SLOT_PACKET, ContainerSetSlotPacket.class); this.registerPacket(ProtocolInfo.CRAFTING_DATA_PACKET, CraftingDataPacket.class); this.registerPacket(ProtocolInfo.CRAFTING_EVENT_PACKET, CraftingEventPacket.class); this.registerPacket(ProtocolInfo.DISCONNECT_PACKET, DisconnectPacket.class); - this.registerPacket(ProtocolInfo.DROP_ITEM_PACKET, DropItemPacket.class); this.registerPacket(ProtocolInfo.ENTITY_EVENT_PACKET, EntityEventPacket.class); this.registerPacket(ProtocolInfo.ENTITY_FALL_PACKET, EntityFallPacket.class); this.registerPacket(ProtocolInfo.EXPLODE_PACKET, ExplodePacket.class); @@ -254,7 +245,9 @@ private void registerPackets() { this.registerPacket(ProtocolInfo.GAME_RULES_CHANGED_PACKET, GameRulesChangedPacket.class); this.registerPacket(ProtocolInfo.HURT_ARMOR_PACKET, HurtArmorPacket.class); this.registerPacket(ProtocolInfo.INTERACT_PACKET, InteractPacket.class); - this.registerPacket(ProtocolInfo.INVENTORY_ACTION_PACKET, InventoryActionPacket.class); + this.registerPacket(ProtocolInfo.INVENTORY_CONTENT_PACKET, InventoryContentPacket.class); + this.registerPacket(ProtocolInfo.INVENTORY_SLOT_PACKET, InventorySlotPacket.class); + this.registerPacket(ProtocolInfo.INVENTORY_TRANSACTION_PACKET, InventoryTransactionPacket.class); this.registerPacket(ProtocolInfo.ITEM_FRAME_DROP_ITEM_PACKET, ItemFrameDropItemPacket.class); this.registerPacket(ProtocolInfo.LEVEL_EVENT_PACKET, LevelEventPacket.class); this.registerPacket(ProtocolInfo.LEVEL_SOUND_EVENT_PACKET, LevelSoundEventPacket.class); @@ -262,16 +255,17 @@ private void registerPackets() { this.registerPacket(ProtocolInfo.MAP_INFO_REQUEST_PACKET, MapInfoRequestPacket.class); this.registerPacket(ProtocolInfo.MOB_ARMOR_EQUIPMENT_PACKET, MobArmorEquipmentPacket.class); this.registerPacket(ProtocolInfo.MOB_EQUIPMENT_PACKET, MobEquipmentPacket.class); + this.registerPacket(ProtocolInfo.MODAL_FORM_REQUEST_PACKET, ModalFormRequestPacket.class); + this.registerPacket(ProtocolInfo.MODAL_FORM_RESPONSE_PACKET, ModalFormResponsePacket.class); this.registerPacket(ProtocolInfo.MOVE_ENTITY_PACKET, MoveEntityPacket.class); this.registerPacket(ProtocolInfo.MOVE_PLAYER_PACKET, MovePlayerPacket.class); this.registerPacket(ProtocolInfo.PLAYER_ACTION_PACKET, PlayerActionPacket.class); this.registerPacket(ProtocolInfo.PLAYER_INPUT_PACKET, PlayerInputPacket.class); this.registerPacket(ProtocolInfo.PLAYER_LIST_PACKET, PlayerListPacket.class); + this.registerPacket(ProtocolInfo.PLAYER_HOTBAR_PACKET, PlayerListPacket.class); this.registerPacket(ProtocolInfo.PLAY_SOUND_PACKET, PlaySoundPacket.class); this.registerPacket(ProtocolInfo.PLAY_STATUS_PACKET, PlayStatusPacket.class); - this.registerPacket(ProtocolInfo.REMOVE_BLOCK_PACKET, RemoveBlockPacket.class); this.registerPacket(ProtocolInfo.REMOVE_ENTITY_PACKET, RemoveEntityPacket.class); - this.registerPacket(ProtocolInfo.REPLACE_ITEM_IN_SLOT_PACKET, ReplaceItemInSlotPacket.class); this.registerPacket(ProtocolInfo.REQUEST_CHUNK_RADIUS_PACKET, RequestChunkRadiusPacket.class); this.registerPacket(ProtocolInfo.RESOURCE_PACKS_INFO_PACKET, ResourcePacksInfoPacket.class); this.registerPacket(ProtocolInfo.RESOURCE_PACK_STACK_PACKET, ResourcePackStackPacket.class); @@ -291,13 +285,14 @@ private void registerPackets() { this.registerPacket(ProtocolInfo.SET_SPAWN_POSITION_PACKET, SetSpawnPositionPacket.class); this.registerPacket(ProtocolInfo.SET_TITLE_PACKET, SetTitlePacket.class); this.registerPacket(ProtocolInfo.SET_TIME_PACKET, SetTimePacket.class); + this.registerPacket(ProtocolInfo.SERVER_SETTINGS_REQUEST_PACKET, ServerSettingsRequestPacket.class); + this.registerPacket(ProtocolInfo.SERVER_SETTINGS_RESPONSE_PACKET, ServerSettingsResponsePacket.class); this.registerPacket(ProtocolInfo.SHOW_CREDITS_PACKET, ShowCreditsPacket.class); this.registerPacket(ProtocolInfo.SPAWN_EXPERIENCE_ORB_PACKET, SpawnExperienceOrbPacket.class); this.registerPacket(ProtocolInfo.START_GAME_PACKET, StartGamePacket.class); this.registerPacket(ProtocolInfo.TAKE_ITEM_ENTITY_PACKET, TakeItemEntityPacket.class); this.registerPacket(ProtocolInfo.TEXT_PACKET, TextPacket.class); this.registerPacket(ProtocolInfo.UPDATE_BLOCK_PACKET, UpdateBlockPacket.class); - this.registerPacket(ProtocolInfo.USE_ITEM_PACKET, UseItemPacket.class); this.registerPacket(ProtocolInfo.UPDATE_TRADE_PACKET, UpdateTradePacket.class); } } diff --git a/src/main/java/cn/nukkit/network/RakNetInterface.java b/src/main/java/cn/nukkit/network/RakNetInterface.java index 8e98db40e8..e5df71d4d0 100644 --- a/src/main/java/cn/nukkit/network/RakNetInterface.java +++ b/src/main/java/cn/nukkit/network/RakNetInterface.java @@ -210,13 +210,16 @@ public void notifyACK(String identifier, int identifierACK) { @Override public void setName(String name) { QueryRegenerateEvent info = this.server.getQueryInformation(); - + String[] names = name.split("!@#"); //Split double names within the program this.handler.sendOption("name", - "MCPE;" + Utils.rtrim(name.replace(";", "\\;"), '\\') + ";" + + "MCPE;" + Utils.rtrim(names[0].replace(";", "\\;"), '\\') + ";" + ProtocolInfo.CURRENT_PROTOCOL + ";" + ProtocolInfo.MINECRAFT_VERSION_NETWORK + ";" + info.getPlayerCount() + ";" + - info.getMaxPlayerCount()); + info.getMaxPlayerCount() + ";" + + this.server.getServerUniqueId().toString() + ";" + + (names.length > 1 ? Utils.rtrim(names[1].replace(";", "\\;"), '\\') : "") + ";" + + Server.getGamemodeString(this.server.getDefaultGamemode(), true) + ";"); } public void setPortCheck(boolean value) { diff --git a/src/main/java/cn/nukkit/network/protocol/AddBehaviorTreePacket.java b/src/main/java/cn/nukkit/network/protocol/AddBehaviorTreePacket.java new file mode 100644 index 0000000000..ce3fa07196 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/AddBehaviorTreePacket.java @@ -0,0 +1,22 @@ +package cn.nukkit.network.protocol; + +public class AddBehaviorTreePacket extends DataPacket { + + public String unknown; + + @Override + public byte pid() { + return ProtocolInfo.ADD_BEHAVIOR_TREE_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + this.reset(); + this.putString(unknown); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/AddEntityPacket.java b/src/main/java/cn/nukkit/network/protocol/AddEntityPacket.java index 98ec3b0f3e..c0df2caf39 100644 --- a/src/main/java/cn/nukkit/network/protocol/AddEntityPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AddEntityPacket.java @@ -39,8 +39,8 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.entityUniqueId); - this.putVarLong(this.entityRuntimeId); + this.putEntityUniqueId(this.entityUniqueId); + this.putEntityRuntimeId(this.entityRuntimeId); this.putUnsignedVarInt(this.type); this.putVector3f(this.x, this.y, this.z); this.putVector3f(this.speedX, this.speedY, this.speedZ); diff --git a/src/main/java/cn/nukkit/network/protocol/AddHangingEntityPacket.java b/src/main/java/cn/nukkit/network/protocol/AddHangingEntityPacket.java deleted file mode 100644 index 2c0c838540..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/AddHangingEntityPacket.java +++ /dev/null @@ -1,39 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.math.BlockVector3; - -public class AddHangingEntityPacket extends DataPacket { - public static final byte NETWORK_ID = ProtocolInfo.ADD_HANGING_ENTITY_PACKET; - - @Override - public byte pid() { - return NETWORK_ID; - } - - public long entityUniqueId; - public long entityRuntimeId; - public int x; - public int y; - public int z; - public int unknown; - - @Override - public void decode() { - this.entityUniqueId = this.getVarLong(); - this.entityRuntimeId = this.getVarLong(); - BlockVector3 v3 = this.getBlockCoords(); - this.x = v3.x; - this.y = v3.y; - this.z = v3.z; - this.unknown = this.getVarInt(); - } - - @Override - public void encode() { - this.reset(); - this.putVarLong(this.entityUniqueId); - this.putVarLong(this.entityRuntimeId); - this.putBlockCoords(this.x, this.y, this.z); - this.putVarInt(this.unknown); - } -} diff --git a/src/main/java/cn/nukkit/network/protocol/AddItemEntityPacket.java b/src/main/java/cn/nukkit/network/protocol/AddItemEntityPacket.java index c22085541c..9a6904e7f5 100644 --- a/src/main/java/cn/nukkit/network/protocol/AddItemEntityPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AddItemEntityPacket.java @@ -35,8 +35,8 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.entityUniqueId); - this.putVarLong(this.entityRuntimeId); + this.putEntityUniqueId(this.entityUniqueId); + this.putEntityRuntimeId(this.entityRuntimeId); this.putSlot(this.item); this.putVector3f(this.x, this.y, this.z); this.putVector3f(this.speedX, this.speedY, this.speedZ); diff --git a/src/main/java/cn/nukkit/network/protocol/AddItemPacket.java b/src/main/java/cn/nukkit/network/protocol/AddItemPacket.java deleted file mode 100644 index 413b6b84f2..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/AddItemPacket.java +++ /dev/null @@ -1,25 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; - -public class AddItemPacket extends DataPacket { - public static final byte NETWORK_ID = ProtocolInfo.ADD_ITEM_PACKET; - - @Override - public byte pid() { - return NETWORK_ID; - } - - public Item item; - - @Override - public void decode() { - - } - - @Override - public void encode() { - this.reset(); - this.putSlot(item); - } -} diff --git a/src/main/java/cn/nukkit/network/protocol/AddPaintingPacket.java b/src/main/java/cn/nukkit/network/protocol/AddPaintingPacket.java index ae7e86c4fb..3c07331314 100644 --- a/src/main/java/cn/nukkit/network/protocol/AddPaintingPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AddPaintingPacket.java @@ -23,9 +23,9 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.entityUniqueId); - this.putVarLong(this.entityRuntimeId); - this.putBlockCoords(this.x, this.y, this.z); + this.putEntityUniqueId(this.entityUniqueId); + this.putEntityRuntimeId(this.entityRuntimeId); + this.putBlockVector3(this.x, this.y, this.z); this.putVarInt(this.direction); this.putString(this.title); } diff --git a/src/main/java/cn/nukkit/network/protocol/AddPlayerPacket.java b/src/main/java/cn/nukkit/network/protocol/AddPlayerPacket.java index 3accf53984..6c211d3db6 100644 --- a/src/main/java/cn/nukkit/network/protocol/AddPlayerPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AddPlayerPacket.java @@ -43,8 +43,8 @@ public void encode() { this.reset(); this.putUUID(this.uuid); this.putString(this.username); - this.putVarLong(this.entityUniqueId); - this.putVarLong(this.entityRuntimeId); + this.putEntityUniqueId(this.entityUniqueId); + this.putEntityRuntimeId(this.entityRuntimeId); this.putVector3f(this.x, this.y, this.z); this.putVector3f(this.speedX, this.speedY, this.speedZ); this.putLFloat(this.pitch); diff --git a/src/main/java/cn/nukkit/network/protocol/AdventureSettingsPacket.java b/src/main/java/cn/nukkit/network/protocol/AdventureSettingsPacket.java index 5d68d7f1a2..16c3ff6802 100644 --- a/src/main/java/cn/nukkit/network/protocol/AdventureSettingsPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AdventureSettingsPacket.java @@ -1,73 +1,97 @@ package cn.nukkit.network.protocol; +import cn.nukkit.Player; + /** * @author Nukkit Project Team */ public class AdventureSettingsPacket extends DataPacket { + public static final byte NETWORK_ID = ProtocolInfo.ADVENTURE_SETTINGS_PACKET; - public boolean worldImmutable; - public boolean noPvp; - public boolean noPvm; - public boolean noMvp; - - public boolean autoJump; - public boolean allowFlight; - public boolean noClip; - public boolean worldBuilder; - public boolean isFlying; - public boolean muted; - - /* - bit mask | flag name - 0x00000001 world_immutable - 0x00000002 no_pvp - 0x00000004 no_pvm - 0x00000008 no_mvp - 0x00000010 ? - 0x00000020 auto_jump - 0x00000040 allow_fly - 0x00000080 noclip - 0x00000100 ? - 0x00000200 is_flying - */ - - public int flags = 0; - public int userPermission; + public static final int PERMISSION_NORMAL = 0; + public static final int PERMISSION_OPERATOR = 1; + public static final int PERMISSION_HOST = 2; + public static final int PERMISSION_AUTOMATION = 3; + public static final int PERMISSION_ADMIN = 4; + //TODO: check level 3 + /** + * This constant is used to identify flags that should be set on the second field. In a sensible world, these + * flags would all be set on the same packet field, but as of MCPE 1.2, the new abilities flags have for some + * reason been assigned a separate field. + */ + public static final int BITFLAG_SECOND_SET = 1 << 16; + + public static final int WORLD_IMMUTABLE = 0x01; + public static final int NO_PVP = 0x02; + public static final int AUTO_JUMP = 0x20; + public static final int ALLOW_FLIGHT = 0x40; + public static final int NO_CLIP = 0x80; + public static final int WORLD_BUILDER = 0x100; + public static final int FLYING = 0x200; + public static final int MUTED = 0x400; + public static final int BUILD_AND_MINE = 0x01 | BITFLAG_SECOND_SET; + public static final int DOORS_AND_SWITCHES = 0x02 | BITFLAG_SECOND_SET; + public static final int OPEN_CONTAINERS = 0x04 | BITFLAG_SECOND_SET; + public static final int ATTACK_PLAYERS = 0x08 | BITFLAG_SECOND_SET; + public static final int ATTACK_MOBS = 0x10 | BITFLAG_SECOND_SET; + public static final int OPERATOR = 0x20 | BITFLAG_SECOND_SET; + public static final int TELEPORT = 0x80 | BITFLAG_SECOND_SET; + + public long flags = 0; + + public long commandPermission = PERMISSION_NORMAL; + + public long flags2 = -1; + + public long playerPermission = Player.PERMISSION_MEMBER; + + public long customFlags; //... + + public long entityUniqueId; //This is a little-endian long, NOT a var-long. (WTF Mojang) - @Override public void decode() { - this.flags = (int) this.getUnsignedVarInt(); - this.userPermission = (int) this.getUnsignedVarInt(); - this.worldImmutable = (this.flags & 1) != 0; - this.noPvp = (this.flags & (1 << 1)) != 0; - this.noPvm = (this.flags & (1 << 2)) != 0; - this.noMvp = (this.flags & (1 << 3)) != 0; - - this.autoJump = (this.flags & (1 << 5)) != 0; - this.allowFlight = (this.flags & (1 << 6)) != 0; - this.noClip = (this.flags & (1 << 7)) != 0; - this.worldBuilder = (this.flags & (1 << 8)) != 0; - this.isFlying = (this.flags & (1 << 9)) != 0; - this.muted = (this.flags & (1 << 10)) != 0; + this.flags = getUnsignedVarInt(); + this.commandPermission = getUnsignedVarInt(); + this.flags2 = getUnsignedVarInt(); + this.playerPermission = getUnsignedVarInt(); + this.customFlags = getUnsignedVarInt(); + this.entityUniqueId = getLLong(); } - @Override public void encode() { this.reset(); - if (this.worldImmutable) this.flags |= 1; - if (this.noPvp) this.flags |= 1 << 1; - if (this.noPvm) this.flags |= 1 << 2; - if (this.noMvp) this.flags |= 1 << 3; - - if (this.autoJump) this.flags |= 1 << 5; - if (this.allowFlight) this.flags |= 1 << 6; - if (this.noClip) this.flags |= 1 << 7; - if (this.worldBuilder) this.flags |= 1 << 8; - if (this.isFlying) this.flags |= 1 << 9; - if (this.muted) this.flags |= 1 << 10; this.putUnsignedVarInt(this.flags); - this.putUnsignedVarInt(this.userPermission); + this.putUnsignedVarInt(this.commandPermission); + this.putUnsignedVarInt(this.flags2); + this.putUnsignedVarInt(this.playerPermission); + this.putUnsignedVarInt(this.customFlags); + this.putLLong(this.entityUniqueId); + } + + public boolean getFlag(int flag) { + if ((flag & BITFLAG_SECOND_SET) != 0) { + return (this.flags2 & flag) != 0; + } + return (this.flags & flag) != 0; + } + + public void setFlag(int flag, boolean value) { + boolean flags = (flag & BITFLAG_SECOND_SET) != 0; + + if (value) { + if (flags) { + this.flags2 |= flag; + } else { + this.flags |= flag; + } + } else { + if (flags) { + this.flags2 &= ~flag; + } else { + this.flags &= ~flag; + } + } } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/AnimatePacket.java b/src/main/java/cn/nukkit/network/protocol/AnimatePacket.java index 8a7efec1f3..87abc99036 100644 --- a/src/main/java/cn/nukkit/network/protocol/AnimatePacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AnimatePacket.java @@ -13,8 +13,8 @@ public class AnimatePacket extends DataPacket { @Override public void decode() { - this.action = (int) this.getUnsignedVarInt(); - this.eid = getVarLong(); + this.action = this.getVarInt(); + this.eid = getEntityRuntimeId(); if ((this.action & 0x80) != 0) { this.unknown = this.getLFloat(); } @@ -23,8 +23,8 @@ public void decode() { @Override public void encode() { this.reset(); - this.putUnsignedVarInt(this.action); - this.putVarLong(this.eid); + this.putVarInt(this.action); + this.putEntityRuntimeId(this.eid); if ((this.action & 0x80) != 0) { this.putLFloat(this.unknown); } diff --git a/src/main/java/cn/nukkit/network/protocol/AvailableCommandsPacket.java b/src/main/java/cn/nukkit/network/protocol/AvailableCommandsPacket.java index 4719a2ff05..02db5e03bc 100644 --- a/src/main/java/cn/nukkit/network/protocol/AvailableCommandsPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/AvailableCommandsPacket.java @@ -1,5 +1,14 @@ package cn.nukkit.network.protocol; +import cn.nukkit.command.data.CommandDataVersions; +import cn.nukkit.command.data.CommandOverload; +import cn.nukkit.command.data.CommandParameter; +import cn.nukkit.utils.BinaryStream; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + /** * author: MagicDroidX * Nukkit Project @@ -7,8 +16,25 @@ public class AvailableCommandsPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.AVAILABLE_COMMANDS_PACKET; - public String commands; //JSON-encoded command data - public String unknown = ""; + public Map commands; + + public static final int ARG_FLAG_VALID = 0x100000; + public static final int ARG_TYPE_INT = 0x01; + public static final int ARG_TYPE_FLOAT = 0x02; + public static final int ARG_TYPE_VALUE = 0x03; + public static final int ARG_TYPE_TARGET = 0x04; + + public static final int ARG_TYPE_STRING = 0x0d; + public static final int ARG_TYPE_POSITION = 0x0e; + + public static final int ARG_TYPE_RAWTEXT = 0x11; + public static final int ARG_TYPE_TEXT = 0x13; + + public static final int ARG_TYPE_JSON = 0x16; + public static final int ARG_TYPE_COMMAND = 0x1d; + + public static final int ARG_FLAG_ENUM = 0x200000; + public static final int ARG_FLAG_TEMPLATE = 0x01000000; @Override public byte pid() { @@ -19,11 +45,58 @@ public byte pid() { public void decode() { } + int aliasCommands = 0; + @Override public void encode() { this.reset(); - this.putString(this.commands); - this.putString(this.unknown); + BinaryStream commandsStream = new BinaryStream(); + this.commands.forEach((name, versions) -> { + if (name.equals("help")) return; + ArrayList aliases = new ArrayList<>(); + aliases.addAll(Arrays.asList(versions.versions.get(0).aliases)); + aliases.add(name); + for (String alias : aliases) { + commandsStream.putString(alias); + commandsStream.putString(versions.versions.get(0).description); + commandsStream.putByte((byte) 0); + commandsStream.putByte((byte) 0); + commandsStream.putLInt(-1); + commandsStream.putUnsignedVarInt(versions.versions.get(0).overloads.size()); + for (CommandOverload overload : versions.versions.get(0).overloads.values()) { + commandsStream.putUnsignedVarInt(overload.input.parameters.length); + for (CommandParameter parameter : overload.input.parameters) { + commandsStream.putString(parameter.name); + commandsStream.putLInt(ARG_FLAG_VALID | getFlag(parameter.type)); + commandsStream.putBoolean(parameter.optional); + } + } + } + aliasCommands += (aliases.size() - 1); + }); + + this.putUnsignedVarInt(0); + this.putUnsignedVarInt(0); + this.putUnsignedVarInt(0); + this.putUnsignedVarInt(this.commands.size() + aliasCommands); + this.put(commandsStream.getBuffer()); } + int getFlag(String type) { + switch (type) { + case CommandParameter.ARG_TYPE_BLOCK_POS: + return ARG_TYPE_POSITION; + case CommandParameter.ARG_TYPE_INT: + return ARG_TYPE_INT; + case CommandParameter.ARG_TYPE_PLAYER: + return ARG_TYPE_TARGET; + case CommandParameter.ARG_TYPE_RAW_TEXT: + return ARG_TYPE_RAWTEXT; + case CommandParameter.ARG_TYPE_STRING: + case CommandParameter.ARG_TYPE_STRING_ENUM: + return ARG_TYPE_STRING; + default: + return 0; + } + } } diff --git a/src/main/java/cn/nukkit/network/protocol/BlockEntityDataPacket.java b/src/main/java/cn/nukkit/network/protocol/BlockEntityDataPacket.java index 92a69abb21..84908c1e4e 100644 --- a/src/main/java/cn/nukkit/network/protocol/BlockEntityDataPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/BlockEntityDataPacket.java @@ -21,7 +21,7 @@ public byte pid() { @Override public void decode() { - BlockVector3 v = this.getBlockCoords(); + BlockVector3 v = this.getBlockVector3(); this.x = v.x; this.y = v.y; this.z = v.z; @@ -31,7 +31,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putBlockCoords(this.x, this.y, this.z); + this.putBlockVector3(this.x, this.y, this.z); this.put(this.namedTag); } } \ No newline at end of file diff --git a/src/main/java/cn/nukkit/network/protocol/BlockEventPacket.java b/src/main/java/cn/nukkit/network/protocol/BlockEventPacket.java index 747cf939c3..411464c220 100644 --- a/src/main/java/cn/nukkit/network/protocol/BlockEventPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/BlockEventPacket.java @@ -26,7 +26,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putBlockCoords(this.x, this.y, this.z); + this.putBlockVector3(this.x, this.y, this.z); this.putVarInt(this.case1); this.putVarInt(this.case2); } diff --git a/src/main/java/cn/nukkit/network/protocol/BlockPickRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/BlockPickRequestPacket.java index 8df148f834..a2cbc823f1 100644 --- a/src/main/java/cn/nukkit/network/protocol/BlockPickRequestPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/BlockPickRequestPacket.java @@ -9,6 +9,7 @@ public class BlockPickRequestPacket extends DataPacket { public int x; public int y; public int z; + public boolean addUserData; public int selectedSlot; @Override @@ -18,10 +19,11 @@ public byte pid() { @Override public void decode() { - BlockVector3 v = this.getBlockCoords(); + BlockVector3 v = this.getSignedBlockPosition(); this.x = v.x; this.y = v.y; this.z = v.z; + this.putBoolean(this.addUserData); this.selectedSlot = this.getByte(); } diff --git a/src/main/java/cn/nukkit/network/protocol/BookEditPacket.java b/src/main/java/cn/nukkit/network/protocol/BookEditPacket.java new file mode 100644 index 0000000000..a52a97a98e --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/BookEditPacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class BookEditPacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.BOOK_EDIT_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/BossEventPacket.java b/src/main/java/cn/nukkit/network/protocol/BossEventPacket.java index 6ab6cf58e5..8bca568b8e 100644 --- a/src/main/java/cn/nukkit/network/protocol/BossEventPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/BossEventPacket.java @@ -7,12 +7,32 @@ public class BossEventPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.BOSS_EVENT_PACKET; - public long eid; - public int type; + /* S2C: Shows the bossbar to the player. */ + public static final int TYPE_SHOW = 0; + /* C2S: Registers a player to a boss fight. */ + public static final int TYPE_REGISTER_PLAYER = 1; + public static final int TYPE_UPDATE = 1; + /* S2C: Removes the bossbar from the client. */ + public static final int TYPE_HIDE = 2; + /* C2S: Unregisters a player from a boss fight. */ + public static final int TYPE_UNREGISTER_PLAYER = 3; + /* S2C: Appears not to be implemented. Currently bar percentage only appears to change in response to the target entity's health. */ + public static final int TYPE_HEALTH_PERCENT = 4; + /* S2C: Also appears to not be implemented. Title clientside sticks as the target entity's nametag, or their entity type name if not set. */ + public static final int TYPE_TITLE = 5; + /* S2C: Not sure on this. Includes color and overlay fields, plus an unknown short. TODO: check this */ + public static final int TYPE_UNKNOWN_6 = 6; + /* S2C: Not implemented :( Intended to alter bar appearance, but these currently produce no effect on clientside whatsoever. */ + public static final int TYPE_TEXTURE = 7; - public static final int ADD = 0; - public static final int UPDATE = 1; - public static final int REMOVE = 2; + public long bossEid; + public int type; + public long playerEid; + public float healthPercent; + public String title = ""; + public short unknown; + public int color; + public int overlay; @Override public byte pid() { @@ -21,13 +41,56 @@ public byte pid() { @Override public void decode() { - + this.bossEid = this.getEntityUniqueId(); + this.type = (int) this.getUnsignedVarInt(); + switch (this.type) { + case TYPE_REGISTER_PLAYER: + case TYPE_UNREGISTER_PLAYER: + this.playerEid = this.getEntityUniqueId(); + break; + case TYPE_SHOW: + this.title = this.getString(); + this.healthPercent = this.getLFloat(); + case TYPE_UNKNOWN_6: + this.unknown = (short) this.getShort(); + case TYPE_TEXTURE: + this.color = (int) this.getUnsignedVarInt(); + this.overlay = (int) this.getUnsignedVarInt(); + break; + case TYPE_HEALTH_PERCENT: + this.healthPercent = this.getLFloat(); + break; + case TYPE_TITLE: + this.title = this.getString(); + break; + } } @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityUniqueId(this.bossEid); this.putUnsignedVarInt(this.type); + switch (this.type) { + case TYPE_REGISTER_PLAYER: + case TYPE_UNREGISTER_PLAYER: + this.putEntityUniqueId(this.playerEid); + break; + case TYPE_SHOW: + this.putString(this.title); + this.putLFloat(this.healthPercent); + case TYPE_UNKNOWN_6: + this.putShort(this.unknown); + case TYPE_TEXTURE: + this.putUnsignedVarInt(this.color); + this.putUnsignedVarInt(this.overlay); + break; + case TYPE_HEALTH_PERCENT: + this.putLFloat(this.healthPercent); + break; + case TYPE_TITLE: + this.putString(this.title); + break; + } } } diff --git a/src/main/java/cn/nukkit/network/protocol/CameraPacket.java b/src/main/java/cn/nukkit/network/protocol/CameraPacket.java new file mode 100644 index 0000000000..7f0c092dc3 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/CameraPacket.java @@ -0,0 +1,25 @@ +package cn.nukkit.network.protocol; + +public class CameraPacket extends DataPacket { + + public long cameraUniqueId; + public long playerUniqueId; + + @Override + public byte pid() { + return ProtocolInfo.CAMERA_PACKET; + } + + @Override + public void decode() { + this.cameraUniqueId = this.getVarLong(); + this.playerUniqueId = this.getVarLong(); + } + + @Override + public void encode() { + this.reset(); + this.putEntityUniqueId(this.cameraUniqueId); + this.putEntityUniqueId(this.playerUniqueId); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ChangeDimensionPacket.java b/src/main/java/cn/nukkit/network/protocol/ChangeDimensionPacket.java index 87a91c2e8e..5341227779 100644 --- a/src/main/java/cn/nukkit/network/protocol/ChangeDimensionPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ChangeDimensionPacket.java @@ -14,7 +14,7 @@ public class ChangeDimensionPacket extends DataPacket { public float y; public float z; - public boolean unknown; + public boolean respawn; @Override public void decode() { @@ -26,7 +26,7 @@ public void encode() { this.reset(); this.putVarInt(this.dimension); this.putVector3f(this.x, this.y, this.z); - this.putBoolean(this.unknown); + this.putBoolean(this.respawn); } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/ClientToServerHandshakePacket.java b/src/main/java/cn/nukkit/network/protocol/ClientToServerHandshakePacket.java new file mode 100644 index 0000000000..d38d0b2b33 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ClientToServerHandshakePacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class ClientToServerHandshakePacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.CLIENT_TO_SERVER_HANDSHAKE_PACKET; + } + + @Override + public void decode() { + //no content + } + + @Override + public void encode() { + + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ClientboundMapItemDataPacket.java b/src/main/java/cn/nukkit/network/protocol/ClientboundMapItemDataPacket.java index 767c395a49..5e8b531477 100644 --- a/src/main/java/cn/nukkit/network/protocol/ClientboundMapItemDataPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ClientboundMapItemDataPacket.java @@ -8,7 +8,7 @@ /** * Created by CreeperFace on 5.3.2017. */ -public class ClientboundMapItemDataPacket extends DataPacket { +public class ClientboundMapItemDataPacket extends DataPacket { //TODO: update to 1.2 public int[] eids = new int[0]; @@ -20,6 +20,8 @@ public class ClientboundMapItemDataPacket extends DataPacket { public int offsetX; public int offsetZ; + public byte dimensionId; + public MapDecorator[] decorators = new MapDecorator[0]; public int[] colors = new int[0]; public BufferedImage image = null; @@ -42,7 +44,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(mapId); + this.putEntityUniqueId(mapId); int update = 0; if (eids.length > 0) { @@ -51,15 +53,18 @@ public void encode() { if (decorators.length > 0) { update |= DECORATIONS_UPDATE; } + if (image != null || colors.length > 0) { update |= TEXTURE_UPDATE; } + this.putUnsignedVarInt(update); + this.putByte(this.dimensionId); if ((update & 0x08) != 0) { //TODO: find out what these are for this.putUnsignedVarInt(eids.length); for (int eid : eids) { - this.putVarInt(eid); + this.putEntityUniqueId(eid); } } if ((update & (TEXTURE_UPDATE | DECORATIONS_UPDATE)) != 0) { @@ -70,11 +75,12 @@ public void encode() { this.putUnsignedVarInt(decorators.length); for (MapDecorator decorator : decorators) { - this.putVarInt((decorator.rotation & 0x0f) | (decorator.icon << 4)); + this.putByte(decorator.rotation); + this.putByte(decorator.icon); this.putByte(decorator.offsetX); this.putByte(decorator.offsetZ); this.putString(decorator.label); - this.putLInt(decorator.color.getRGB()); + this.putVarInt(decorator.color.getRGB()); } } @@ -84,6 +90,8 @@ public void encode() { this.putVarInt(offsetX); this.putVarInt(offsetZ); + this.putUnsignedVarInt(width * height); + if (image != null) { for (int y = 0; y < width; y++) { for (int x = 0; x < height; x++) { diff --git a/src/main/java/cn/nukkit/network/protocol/CommandBlockUpdatePacket.java b/src/main/java/cn/nukkit/network/protocol/CommandBlockUpdatePacket.java new file mode 100644 index 0000000000..e87893e35c --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/CommandBlockUpdatePacket.java @@ -0,0 +1,62 @@ +package cn.nukkit.network.protocol; + +import cn.nukkit.math.BlockVector3; + +public class CommandBlockUpdatePacket extends DataPacket { + + public boolean isBlock; + public int x; + public int y; + public int z; + public int commandBlockMode; + public boolean isRedstoneMode; + public boolean isConditional; + public long minecartEid; + public String command; + public String lastOutput; + public String name; + public boolean shouldTrackOutput; + + @Override + public byte pid() { + return ProtocolInfo.COMMAND_BLOCK_UPDATE_PACKET; + } + + @Override + public void decode() { + this.isBlock = this.getBoolean(); + if (this.isBlock) { + BlockVector3 v = this.getBlockVector3(); + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.commandBlockMode = (int) this.getUnsignedVarInt(); + this.isRedstoneMode = this.getBoolean(); + this.isConditional = this.getBoolean(); + } else { + this.minecartEid = this.getEntityRuntimeId(); + } + this.command = this.getString(); + this.lastOutput = this.getString(); + this.name = this.getString(); + this.shouldTrackOutput = this.getBoolean(); + } + + @Override + public void encode() { + this.reset(); + this.putBoolean(this.isBlock); + if (this.isBlock) { + this.putBlockVector3(this.x, this.y, this.z); + this.putUnsignedVarInt(this.commandBlockMode); + this.putBoolean(this.isRedstoneMode); + this.putBoolean(this.isConditional); + } else { + this.putEntityRuntimeId(this.minecartEid); + } + this.putString(this.command); + this.putString(this.lastOutput); + this.putString(this.name); + this.putBoolean(this.shouldTrackOutput); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/CommandRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/CommandRequestPacket.java new file mode 100644 index 0000000000..28673d2ac1 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/CommandRequestPacket.java @@ -0,0 +1,45 @@ +package cn.nukkit.network.protocol; + +/** + * author: MagicDroidX + * Nukkit Project + */ +public class CommandRequestPacket extends DataPacket { + + public static final byte NETWORK_ID = ProtocolInfo.COMMAND_REQUEST_PACKET; + + public static final int TYPE_PLAYER = 0; + public static final int TYPE_COMMAND_BLOCK = 1; + public static final int TYPE_MINECART_COMMAND_BLOCK = 2; + public static final int TYPE_DEV_CONSOLE = 3; + public static final int TYPE_AUTOMATION_PLAYER = 4; + public static final int TYPE_CLIENT_AUTOMATION = 5; + public static final int TYPE_DEDICATED_SERVER = 6; + public static final int TYPE_ENTITY = 7; + public static final int TYPE_VIRTUAL = 8; + public static final int TYPE_GAME_ARGUMENT = 9; + public static final int TYPE_INTERNAL = 10; + + public String command; + public int type; + public String requestId; + public long playerUniqueId; + + @Override + public byte pid() { + return NETWORK_ID; + } + + @Override + public void decode() { + this.command = this.getString(); + this.type = this.getVarInt(); + this.requestId = this.getString(); + this.playerUniqueId = this.getVarLong(); + } + + @Override + public void encode() { + } + +} diff --git a/src/main/java/cn/nukkit/network/protocol/CommandStepPacket.java b/src/main/java/cn/nukkit/network/protocol/CommandStepPacket.java deleted file mode 100644 index d85d26104d..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/CommandStepPacket.java +++ /dev/null @@ -1,62 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.command.data.CommandArgs; -import com.google.gson.Gson; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public class CommandStepPacket extends DataPacket { - - public static final byte NETWORK_ID = ProtocolInfo.COMMAND_STEP_PACKET; - - /** - * unknown (string) - * unknown (string) - * unknown (uvarint) - * unknown (uvarint) - * unknown (bool) - * unknown (uvarint64) - * unknown (string) - * unknown (string) - * https://gist.github.com/dktapps/8285b93af4ca38e0104bfeb9a6c87afd - */ - - - public String command; - public String overload; - public long uvarint1; - public long currentStep; - public boolean done; - public long clientId; - public CommandArgs args = new CommandArgs(); //JSON formatted command arguments - public String outputJson; - - @Override - public byte pid() { - return NETWORK_ID; - } - - @Override - public void decode() { - this.command = this.getString(); - this.overload = this.getString(); - this.uvarint1 = this.getUnsignedVarInt(); - this.currentStep = this.getUnsignedVarInt(); - this.done = this.getBoolean(); - this.clientId = this.getVarLong(); - String argsString = this.getString(); - this.args = new Gson().fromJson(argsString, CommandArgs.class); - this.outputJson = this.getString(); - while (!this.feof()) { - this.getByte(); //prevent assertion errors. TODO: find out why there are always 3 extra bytes at the end of this packet. - } - - } - - @Override - public void encode() { - } - -} diff --git a/src/main/java/cn/nukkit/network/protocol/ContainerClosePacket.java b/src/main/java/cn/nukkit/network/protocol/ContainerClosePacket.java index 2c648e4199..d9646cd20c 100644 --- a/src/main/java/cn/nukkit/network/protocol/ContainerClosePacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ContainerClosePacket.java @@ -12,16 +12,16 @@ public byte pid() { return NETWORK_ID; } - public int windowid; + public int windowId; @Override public void decode() { - this.windowid = this.getByte(); + this.windowId = this.getByte(); } @Override public void encode() { this.reset(); - this.putByte((byte) this.windowid); + this.putByte((byte) this.windowId); } } diff --git a/src/main/java/cn/nukkit/network/protocol/ContainerOpenPacket.java b/src/main/java/cn/nukkit/network/protocol/ContainerOpenPacket.java index 9d64bf2124..9ba871c569 100644 --- a/src/main/java/cn/nukkit/network/protocol/ContainerOpenPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ContainerOpenPacket.java @@ -1,5 +1,7 @@ package cn.nukkit.network.protocol; +import cn.nukkit.math.BlockVector3; + /** * author: MagicDroidX * Nukkit Project @@ -12,24 +14,30 @@ public byte pid() { return NETWORK_ID; } - public byte windowid; - public byte type; + public int windowId; + public int type; public int x; public int y; public int z; - public final long entityId = -1; + public long entityId = -1; @Override public void decode() { - + this.windowId = this.getByte(); + this.type = this.getByte(); + BlockVector3 v = this.getBlockVector3(); + this.x = v.x; + this.y = v.y; + this.z = v.z; + this.entityId = this.getEntityUniqueId(); } @Override public void encode() { this.reset(); - this.putByte(this.windowid); - this.putByte(this.type); - this.putBlockCoords(this.x, this.y, this.z); - this.putVarLong(this.entityId); + this.putByte((byte) this.windowId); + this.putByte((byte) this.type); + this.putBlockVector3(this.x, this.y, this.z); + this.putEntityUniqueId(this.entityId); } } diff --git a/src/main/java/cn/nukkit/network/protocol/ContainerSetContentPacket.java b/src/main/java/cn/nukkit/network/protocol/ContainerSetContentPacket.java deleted file mode 100644 index 73d92944af..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/ContainerSetContentPacket.java +++ /dev/null @@ -1,79 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public class ContainerSetContentPacket extends DataPacket { - public static final byte NETWORK_ID = ProtocolInfo.CONTAINER_SET_CONTENT_PACKET; - - @Override - public byte pid() { - return NETWORK_ID; - } - - public static final byte SPECIAL_INVENTORY = 0; - public static final byte SPECIAL_ARMOR = 0x78; - public static final byte SPECIAL_CREATIVE = 0x79; - public static final byte SPECIAL_HOTBAR = 0x7a; - public static final byte SPECIAL_FIXED_INVENTORY = 0x7b; - - public long windowid; - public long eid; - public Item[] slots = new Item[0]; - public int[] hotbar = new int[0]; - - @Override - public DataPacket clean() { - this.slots = new Item[0]; - this.hotbar = new int[0]; - return super.clean(); - } - - @Override - public void decode() { - this.windowid = (int) this.getUnsignedVarInt(); - this.eid = this.getVarLong(); - int count = (int) this.getUnsignedVarInt(); - this.slots = new Item[count]; - - for (int s = 0; s < count && !this.feof(); ++s) { - this.slots[s] = this.getSlot(); - } - - count = (int) this.getUnsignedVarInt(); - this.hotbar = new int[count]; - for (int s = 0; s < count && !this.feof(); ++s) { - this.hotbar[s] = this.getVarInt(); - } - } - - @Override - public void encode() { - this.reset(); - this.putUnsignedVarInt(this.windowid); - this.putVarLong(this.eid); - this.putUnsignedVarInt(this.slots.length); - for (Item slot : this.slots) { - this.putSlot(slot); - } - - if (this.windowid == SPECIAL_INVENTORY && this.hotbar.length > 0) { - this.putUnsignedVarInt(this.hotbar.length); - for (int slot : this.hotbar) { - this.putVarInt(slot); - } - } else { - this.putUnsignedVarInt(0); - } - } - - @Override - public ContainerSetContentPacket clone() { - ContainerSetContentPacket pk = (ContainerSetContentPacket) super.clone(); - pk.slots = this.slots.clone(); - return pk; - } -} diff --git a/src/main/java/cn/nukkit/network/protocol/ContainerSetDataPacket.java b/src/main/java/cn/nukkit/network/protocol/ContainerSetDataPacket.java index 0af0d573a4..97458e3e82 100644 --- a/src/main/java/cn/nukkit/network/protocol/ContainerSetDataPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ContainerSetDataPacket.java @@ -7,12 +7,22 @@ public class ContainerSetDataPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.CONTAINER_SET_DATA_PACKET; + public static final int PROPERTY_FURNACE_TICK_COUNT = 0; + public static final int PROPERTY_FURNACE_LIT_TIME = 1; + public static final int PROPERTY_FURNACE_LIT_DURATION = 2; + //TODO: check property 3 + public static final int PROPERTY_FURNACE_FUEL_AUX = 4; + + public static final int PROPERTY_BREWING_STAND_BREW_TIME = 0; + public static final int PROPERTY_BREWING_STAND_FUEL_AMOUNT = 1; + public static final int PROPERTY_BREWING_STAND_FUEL_TOTAL = 2; + @Override public byte pid() { return NETWORK_ID; } - public byte windowid; + public int windowId; public int property; public int value; @@ -24,7 +34,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putByte(this.windowid); + this.putByte((byte) this.windowId); this.putVarInt(this.property); this.putVarInt(this.value); } diff --git a/src/main/java/cn/nukkit/network/protocol/ContainerSetSlotPacket.java b/src/main/java/cn/nukkit/network/protocol/ContainerSetSlotPacket.java deleted file mode 100644 index b78648c5bb..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/ContainerSetSlotPacket.java +++ /dev/null @@ -1,41 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; - -/** - * author: MagicDroidX - * Nukkit Project - */ -public class ContainerSetSlotPacket extends DataPacket { - public static final byte NETWORK_ID = ProtocolInfo.CONTAINER_SET_SLOT_PACKET; - - @Override - public byte pid() { - return NETWORK_ID; - } - - public int windowid; - public int slot; - public int hotbarSlot; - public Item item; - public int selectedSlot; - - @Override - public void decode() { - this.windowid = this.getByte(); - this.slot = this.getVarInt(); - this.hotbarSlot = this.getVarInt(); - this.item = this.getSlot(); - this.selectedSlot = this.getByte(); - } - - @Override - public void encode() { - this.reset(); - this.putByte((byte) this.windowid); - this.putVarInt(this.slot); - this.putVarInt(this.hotbarSlot); - this.putSlot(this.item); - this.putByte((byte) this.selectedSlot); - } -} diff --git a/src/main/java/cn/nukkit/network/protocol/CraftingEventPacket.java b/src/main/java/cn/nukkit/network/protocol/CraftingEventPacket.java index a500542d61..e9530edd56 100644 --- a/src/main/java/cn/nukkit/network/protocol/CraftingEventPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/CraftingEventPacket.java @@ -12,6 +12,13 @@ public class CraftingEventPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.CRAFTING_EVENT_PACKET; + public static final int TYPE_SHAPELESS = 0; + public static final int TYPE_SHAPED = 1; + public static final int TYPE_FURNACE = 2; + public static final int TYPE_FURNACE_DATA = 3; + public static final int TYPE_MULTI = 4; + public static final int TYPE_SHULKER_BOX = 5; + public int windowId; public int type; public UUID id; @@ -22,7 +29,7 @@ public class CraftingEventPacket extends DataPacket { @Override public void decode() { this.windowId = this.getByte(); - this.type = (int) this.getUnsignedVarInt(); + this.type = this.getVarInt(); this.id = this.getUUID(); int inputSize = (int) this.getUnsignedVarInt(); diff --git a/src/main/java/cn/nukkit/network/protocol/DataPacket.java b/src/main/java/cn/nukkit/network/protocol/DataPacket.java index da40136b85..f2570e5573 100644 --- a/src/main/java/cn/nukkit/network/protocol/DataPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/DataPacket.java @@ -27,6 +27,7 @@ public abstract class DataPacket extends BinaryStream implements Cloneable { public void reset() { super.reset(); this.putByte(this.pid()); + this.putShort(0); } public void setChannel(int channel) { diff --git a/src/main/java/cn/nukkit/network/protocol/DropItemPacket.java b/src/main/java/cn/nukkit/network/protocol/DropItemPacket.java deleted file mode 100644 index 9cd730ad79..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/DropItemPacket.java +++ /dev/null @@ -1,31 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; - -/** - * @author Nukkit Project Team - */ -public class DropItemPacket extends DataPacket { - - public static final byte NETWORK_ID = ProtocolInfo.DROP_ITEM_PACKET; - - public int type; - public Item item; - - @Override - public void decode() { - this.type = this.getByte(); - this.item = this.getSlot(); - } - - @Override - public void encode() { - - } - - @Override - public byte pid() { - return NETWORK_ID; - } - -} diff --git a/src/main/java/cn/nukkit/network/protocol/EntityEventPacket.java b/src/main/java/cn/nukkit/network/protocol/EntityEventPacket.java index 074338725c..2ad19b9e17 100644 --- a/src/main/java/cn/nukkit/network/protocol/EntityEventPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/EntityEventPacket.java @@ -5,24 +5,31 @@ * Nukkit Project */ public class EntityEventPacket extends DataPacket { - public static final byte NETWORK_ID = ProtocolInfo.ENTITY_EVENT_PACKET; + public static final int NETWORK_ID = ProtocolInfo.ENTITY_EVENT_PACKET; - public static final byte HURT_ANIMATION = 2; - public static final byte DEATH_ANIMATION = 3; + public static final int HURT_ANIMATION = 2; + public static final int DEATH_ANIMATION = 3; - public static final byte TAME_FAIL = 6; - public static final byte TAME_SUCCESS = 7; - public static final byte SHAKE_WET = 8; - public static final byte USE_ITEM = 9; - public static final byte EAT_GRASS_ANIMATION = 10; - public static final byte FISH_HOOK_BUBBLE = 11; - public static final byte FISH_HOOK_POSITION = 12; - public static final byte FISH_HOOK_HOOK = 13; - public static final byte FISH_HOOK_TEASE = 14; - public static final byte SQUID_INK_CLOUD = 15; - public static final byte AMBIENT_SOUND = 16; - public static final byte RESPAWN = 17; + public static final int TAME_FAIL = 6; + public static final int TAME_SUCCESS = 7; + public static final int SHAKE_WET = 8; + public static final int USE_ITEM = 9; + public static final int EAT_GRASS_ANIMATION = 10; + public static final int FISH_HOOK_BUBBLE = 11; + public static final int FISH_HOOK_POSITION = 12; + public static final int FISH_HOOK_HOOK = 13; + public static final int FISH_HOOK_TEASE = 14; + public static final int SQUID_INK_CLOUD = 15; + + public static final int AMBIENT_SOUND = 17; + public static final int RESPAWN = 18; + + public static final int ENCHANT = 34; + + public static final byte EATING_ITEM = 57; + + public static final byte UNKNOWN1 = 66; @Override public byte pid() { @@ -30,21 +37,21 @@ public byte pid() { } public long eid; - public byte event; - public long unknown; + public int event; + public int data; @Override public void decode() { - this.eid = this.getVarLong(); - this.event = (byte) this.getByte(); - this.unknown = this.getUnsignedVarInt(); + this.eid = this.getEntityRuntimeId(); + this.event = this.getByte(); + this.data = this.getVarInt(); } @Override public void encode() { this.reset(); - this.putVarLong(this.eid); - this.putByte(this.event); - this.putUnsignedVarInt(this.unknown); + this.putEntityRuntimeId(this.eid); + this.putByte((byte) this.event); + this.putVarInt((byte) this.data); } } diff --git a/src/main/java/cn/nukkit/network/protocol/EntityFallPacket.java b/src/main/java/cn/nukkit/network/protocol/EntityFallPacket.java index ae876b029d..086fc56a6b 100644 --- a/src/main/java/cn/nukkit/network/protocol/EntityFallPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/EntityFallPacket.java @@ -9,7 +9,7 @@ public class EntityFallPacket extends DataPacket { @Override public void decode() { - this.eid = this.getVarLong(); + this.eid = this.getEntityRuntimeId(); this.fallDistance = this.getLFloat(); this.unknown = this.getBoolean(); } diff --git a/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java new file mode 100644 index 0000000000..d4abec9571 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/EntityPickRequestPacket.java @@ -0,0 +1,21 @@ +package cn.nukkit.network.protocol; + +public class EntityPickRequestPacket extends DataPacket { + + public static final byte NETWORK_ID = ProtocolInfo.ENTITY_PICK_REQUEST_PACKET; + + @Override + public byte pid() { + return NETWORK_ID; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ExplodePacket.java b/src/main/java/cn/nukkit/network/protocol/ExplodePacket.java index a55e33ef89..922aaff2bd 100644 --- a/src/main/java/cn/nukkit/network/protocol/ExplodePacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ExplodePacket.java @@ -40,7 +40,7 @@ public void encode() { this.putUnsignedVarInt(this.records.length); if (this.records.length > 0) { for (Vector3 record : records) { - this.putBlockCoords((int) record.x, (int) record.y, (int) record.z); + this.putBlockVector3((int) record.x, (int) record.y, (int) record.z); } } } diff --git a/src/main/java/cn/nukkit/network/protocol/GUIDataPickItemPacket.java b/src/main/java/cn/nukkit/network/protocol/GUIDataPickItemPacket.java new file mode 100644 index 0000000000..6cbc80ca1f --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/GUIDataPickItemPacket.java @@ -0,0 +1,22 @@ +package cn.nukkit.network.protocol; + +public class GUIDataPickItemPacket extends DataPacket { + + public int hotbarSlot; + + @Override + public byte pid() { + return ProtocolInfo.GUI_DATA_PICK_ITEM_PACKET; + } + + @Override + public void encode() { + this.reset(); + this.putLInt(this.hotbarSlot); + } + + @Override + public void decode() { + this.hotbarSlot = this.getLInt(); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/InitiateWebSocketConnectionPacket.java b/src/main/java/cn/nukkit/network/protocol/InitiateWebSocketConnectionPacket.java new file mode 100644 index 0000000000..4cb9bd6333 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/InitiateWebSocketConnectionPacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class InitiateWebSocketConnectionPacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.INITIATE_WEB_SOCKET_CONNECTION_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/InteractPacket.java b/src/main/java/cn/nukkit/network/protocol/InteractPacket.java index 6d49409e24..e909160c28 100644 --- a/src/main/java/cn/nukkit/network/protocol/InteractPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/InteractPacket.java @@ -7,27 +7,25 @@ public class InteractPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.INTERACT_PACKET; - public static final byte ACTION_RIGHT_CLICK = 1; - public static final byte ACTION_LEFT_CLICK = 2; - public static final byte ACTION_VEHICLE_EXIT = 3; - public static final byte ACTION_MOUSEOVER = 4; + public static final int ACTION_VEHICLE_EXIT = 3; + public static final int ACTION_MOUSEOVER = 4; - public static final byte ACTION_OPEN_INVENTORY = 6; + public static final int ACTION_OPEN_INVENTORY = 6; - public byte action; + public int action; public long target; @Override public void decode() { - this.action = (byte) this.getByte(); - this.target = this.getVarLong(); + this.action = this.getByte(); + this.target = this.getEntityRuntimeId(); } @Override public void encode() { this.reset(); - this.putByte(this.action); - this.putVarLong(this.target); + this.putByte((byte) this.action); + this.putEntityRuntimeId(this.target); } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/InventoryActionPacket.java b/src/main/java/cn/nukkit/network/protocol/InventoryActionPacket.java deleted file mode 100644 index e7492223ee..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/InventoryActionPacket.java +++ /dev/null @@ -1,32 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; - -public class InventoryActionPacket extends DataPacket { - - public static final byte NETWORK_ID = ProtocolInfo.INVENTORY_ACTION_PACKET; - - public int actionId; - public Item item; - public int enchantmentId; - public int enchantmentLevel; - - @Override - public void decode() { - - } - - @Override - public void encode() { - this.reset(); - this.putUnsignedVarInt(this.actionId); - this.putSlot(this.item); - this.putVarInt(this.enchantmentId); - this.putVarInt(this.enchantmentLevel); - } - - @Override - public byte pid() { - return NETWORK_ID; - } -} diff --git a/src/main/java/cn/nukkit/network/protocol/InventoryContentPacket.java b/src/main/java/cn/nukkit/network/protocol/InventoryContentPacket.java new file mode 100644 index 0000000000..18b831866e --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/InventoryContentPacket.java @@ -0,0 +1,60 @@ +package cn.nukkit.network.protocol; + +import cn.nukkit.item.Item; + +/** + * author: MagicDroidX + * Nukkit Project + */ +public class InventoryContentPacket extends DataPacket { + public static final byte NETWORK_ID = ProtocolInfo.INVENTORY_CONTENT_PACKET; + + @Override + public byte pid() { + return NETWORK_ID; + } + + public static final int SPECIAL_INVENTORY = 0; + public static final int SPECIAL_OFFHAND = 0x77; + public static final int SPECIAL_ARMOR = 0x78; + public static final int SPECIAL_CREATIVE = 0x79; + public static final int SPECIAL_HOTBAR = 0x7a; + public static final int SPECIAL_FIXED_INVENTORY = 0x7b; + + public int inventoryId; + public Item[] slots = new Item[0]; + + @Override + public DataPacket clean() { + this.slots = new Item[0]; + return super.clean(); + } + + @Override + public void decode() { + this.inventoryId = (int) this.getUnsignedVarInt(); + int count = (int) this.getUnsignedVarInt(); + this.slots = new Item[count]; + + for (int s = 0; s < count && !this.feof(); ++s) { + this.slots[s] = this.getSlot(); + } + } + + @Override + public void encode() { + this.reset(); + this.putUnsignedVarInt(this.inventoryId); + this.putUnsignedVarInt(this.slots.length); + for (Item slot : this.slots) { + this.putSlot(slot); + } + } + + @Override + public InventoryContentPacket clone() { + InventoryContentPacket pk = (InventoryContentPacket) super.clone(); + pk.slots = this.slots.clone(); + return pk; + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/InventorySlotPacket.java b/src/main/java/cn/nukkit/network/protocol/InventorySlotPacket.java new file mode 100644 index 0000000000..ae8a9d6e0a --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/InventorySlotPacket.java @@ -0,0 +1,35 @@ +package cn.nukkit.network.protocol; + +import cn.nukkit.item.Item; + +/** + * author: MagicDroidX + * Nukkit Project + */ +public class InventorySlotPacket extends DataPacket { + public static final byte NETWORK_ID = ProtocolInfo.INVENTORY_SLOT_PACKET; + + @Override + public byte pid() { + return NETWORK_ID; + } + + public int inventoryId; + public int slot; + public Item item; + + @Override + public void decode() { + this.inventoryId = (int) this.getUnsignedVarInt(); + this.slot = (int) this.getUnsignedVarInt(); + this.item = this.getSlot(); + } + + @Override + public void encode() { + this.reset(); + this.putUnsignedVarInt((byte) this.inventoryId); + this.putUnsignedVarInt(this.slot); + this.putSlot(this.item); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/InventoryTransactionPacket.java b/src/main/java/cn/nukkit/network/protocol/InventoryTransactionPacket.java new file mode 100644 index 0000000000..88ae0646de --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/InventoryTransactionPacket.java @@ -0,0 +1,144 @@ +package cn.nukkit.network.protocol; + +import cn.nukkit.inventory.transaction.data.ReleaseItemData; +import cn.nukkit.inventory.transaction.data.TransactionData; +import cn.nukkit.inventory.transaction.data.UseItemData; +import cn.nukkit.inventory.transaction.data.UseItemOnEntityData; +import cn.nukkit.network.protocol.types.NetworkInventoryAction; + +public class InventoryTransactionPacket extends DataPacket { + + public static final int TYPE_NORMAL = 0; + public static final int TYPE_MISMATCH = 1; + public static final int TYPE_USE_ITEM = 2; + public static final int TYPE_USE_ITEM_ON_ENTITY = 3; + public static final int TYPE_RELEASE_ITEM = 4; + + public static final int USE_ITEM_ACTION_CLICK_BLOCK = 0; + public static final int USE_ITEM_ACTION_CLICK_AIR = 1; + public static final int USE_ITEM_ACTION_BREAK_BLOCK = 2; + + public static final int RELEASE_ITEM_ACTION_RELEASE = 0; //bow shoot + public static final int RELEASE_ITEM_ACTION_CONSUME = 1; //eat food, drink potion + + public static final int USE_ITEM_ON_ENTITY_ACTION_INTERACT = 0; + public static final int USE_ITEM_ON_ENTITY_ACTION_ATTACK = 1; + + + public static final int ACTION_MAGIC_SLOT_DROP_ITEM = 0; + public static final int ACTION_MAGIC_SLOT_PICKUP_ITEM = 1; + + public static final int ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM = 0; + public static final int ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM = 1; + + public int transactionType; + public NetworkInventoryAction[] actions; + public TransactionData transactionData; + + @Override + public byte pid() { + return ProtocolInfo.INVENTORY_TRANSACTION_PACKET; + } + + @Override + public void encode() { + this.reset(); + this.putUnsignedVarInt(this.transactionType); + + this.putUnsignedVarInt(this.actions.length); + for (NetworkInventoryAction action : this.actions) { + action.write(this); + } + + switch (this.transactionType) { + case TYPE_NORMAL: + case TYPE_MISMATCH: + break; + case TYPE_USE_ITEM: + UseItemData useItemData = (UseItemData) this.transactionData; + + this.putUnsignedVarInt(useItemData.actionType); + this.putBlockVector3(useItemData.blockPos); + this.putBlockFace(useItemData.face); + this.putVarInt(useItemData.hotbarSlot); + this.putSlot(useItemData.itemInHand); + this.putVector3f(useItemData.playerPos.asVector3f()); + this.putVector3f(useItemData.clickPos); + break; + case TYPE_USE_ITEM_ON_ENTITY: + UseItemOnEntityData useItemOnEntityData = (UseItemOnEntityData) this.transactionData; + + this.putEntityRuntimeId(useItemOnEntityData.entityRuntimeId); + this.putUnsignedVarInt(useItemOnEntityData.actionType); + this.putVarInt(useItemOnEntityData.hotbarSlot); + this.putSlot(useItemOnEntityData.itemInHand); + this.putVector3f(useItemOnEntityData.vector1.asVector3f()); + this.putVector3f(useItemOnEntityData.vector2.asVector3f()); + break; + case TYPE_RELEASE_ITEM: + ReleaseItemData releaseItemData = (ReleaseItemData) this.transactionData; + + this.putUnsignedVarInt(releaseItemData.actionType); + this.putVarInt(releaseItemData.hotbarSlot); + this.putSlot(releaseItemData.itemInHand); + this.putVector3f(releaseItemData.headRot.asVector3f()); + break; + default: + throw new RuntimeException("Unknown transaction type " + this.transactionType); + } + } + + @Override + public void decode() { + this.transactionType = (int) this.getUnsignedVarInt(); + + this.actions = new NetworkInventoryAction[(int) this.getUnsignedVarInt()]; + for (int i = 0; i < this.actions.length; i++) { + this.actions[i] = new NetworkInventoryAction().read(this); + } + + switch (this.transactionType) { + case TYPE_NORMAL: + case TYPE_MISMATCH: + //Regular ComplexInventoryTransaction doesn't read any extra data + break; + case TYPE_USE_ITEM: + UseItemData itemData = new UseItemData(); + + itemData.actionType = (int) this.getUnsignedVarInt(); + itemData.blockPos = this.getBlockVector3(); + itemData.face = this.getBlockFace(); + itemData.hotbarSlot = this.getVarInt(); + itemData.itemInHand = this.getSlot(); + itemData.playerPos = this.getVector3f().asVector3(); + itemData.clickPos = this.getVector3f(); + + this.transactionData = itemData; + break; + case TYPE_USE_ITEM_ON_ENTITY: + UseItemOnEntityData useItemOnEntityData = new UseItemOnEntityData(); + + useItemOnEntityData.entityRuntimeId = this.getEntityRuntimeId(); + useItemOnEntityData.actionType = (int) this.getUnsignedVarInt(); + useItemOnEntityData.hotbarSlot = this.getVarInt(); + useItemOnEntityData.itemInHand = this.getSlot(); + useItemOnEntityData.vector1 = this.getVector3f().asVector3(); + useItemOnEntityData.vector2 = this.getVector3f().asVector3(); + + this.transactionData = useItemOnEntityData; + break; + case TYPE_RELEASE_ITEM: + ReleaseItemData releaseItemData = new ReleaseItemData(); + + releaseItemData.actionType = (int) getUnsignedVarInt(); + releaseItemData.hotbarSlot = getVarInt(); + releaseItemData.itemInHand = getSlot(); + releaseItemData.headRot = this.getVector3f().asVector3(); + + this.transactionData = releaseItemData; + break; + default: + throw new RuntimeException("Unknown transaction type " + this.transactionType); + } + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ItemFrameDropItemPacket.java b/src/main/java/cn/nukkit/network/protocol/ItemFrameDropItemPacket.java index ce0ca5c807..1aa0b9458e 100644 --- a/src/main/java/cn/nukkit/network/protocol/ItemFrameDropItemPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ItemFrameDropItemPacket.java @@ -15,7 +15,7 @@ public class ItemFrameDropItemPacket extends DataPacket { @Override public void decode() { - BlockVector3 v = this.getBlockCoords(); + BlockVector3 v = this.getBlockVector3(); this.z = v.z; this.y = v.y; this.x = v.x; diff --git a/src/main/java/cn/nukkit/network/protocol/LevelEventPacket.java b/src/main/java/cn/nukkit/network/protocol/LevelEventPacket.java index 882233b3e3..421958dcd1 100644 --- a/src/main/java/cn/nukkit/network/protocol/LevelEventPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/LevelEventPacket.java @@ -32,7 +32,7 @@ public class LevelEventPacket extends DataPacket { public static final int EVENT_SOUND_ITEM_THROWN = 1031; public static final int EVENT_SOUND_PORTAL = 1032; - + public static final int EVENT_SOUND_ITEM_FRAME_ITEM_ADDED = 1040; public static final int EVENT_SOUND_ITEM_FRAME_PLACED = 1041; public static final int EVENT_SOUND_ITEM_FRAME_REMOVED = 1042; @@ -41,14 +41,19 @@ public class LevelEventPacket extends DataPacket { public static final int EVENT_SOUND_CAMERA_TAKE_PICTURE = 1050; public static final int EVENT_SOUND_EXPERIENCE_ORB = 1051; - public static final int EVENT_SOUND_BLOCK_PLACE = 1052; + public static final int EVENT_SOUND_TOTEM = 1052; + + public static final int EVENT_SOUND_ARMOR_STAND_BREAK = 1060; + public static final int EVENT_SOUND_ARMOR_STAND_HIT = 1061; + public static final int EVENT_SOUND_ARMOR_STAND_FALL = 1062; + public static final int EVENT_SOUND_ARMOR_STAND_PLACE = 1063; public static final int EVENT_GUARDIAN_CURSE = 2006; - + public static final int EVENT_PARTICLE_BLOCK_FORCE_FIELD = 2008; public static final int EVENT_PARTICLE_PUNCH_BLOCK = 2014; - + public static final int EVENT_SOUND_BUTTON_CLICK = 3500; public static final int EVENT_SOUND_EXPLODE = 3501; public static final int EVENT_CAULDRON_DYE_ARMOR = 3502; @@ -58,7 +63,8 @@ public class LevelEventPacket extends DataPacket { public static final int EVENT_SOUND_SPLASH = 3506; public static final int EVENT_CAULDRON_TAKE_WATER = 3507; public static final int EVENT_CAULDRON_ADD_DYE = 3508; - + public static final int EVENT_CAULDRON_CLEAN_BANNER = 3509; + public static final int EVENT_PARTICLE_SHOOT = 2000; public static final int EVENT_PARTICLE_DESTROY = 2001; public static final int EVENT_PARTICLE_SPLASH = 2002; @@ -89,7 +95,7 @@ public class LevelEventPacket extends DataPacket { public float x = 0; public float y = 0; public float z = 0; - public int data; + public int data = 0; @Override public byte pid() { diff --git a/src/main/java/cn/nukkit/network/protocol/LevelSoundEventPacket.java b/src/main/java/cn/nukkit/network/protocol/LevelSoundEventPacket.java index 5d6661f293..9952f18e46 100644 --- a/src/main/java/cn/nukkit/network/protocol/LevelSoundEventPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/LevelSoundEventPacket.java @@ -6,123 +6,176 @@ public class LevelSoundEventPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.LEVEL_SOUND_EVENT_PACKET; - public static final byte SOUND_ITEM_USE_ON = 0; - public static final byte SOUND_HIT = 1; - public static final byte SOUND_STEP = 2; - public static final byte SOUND_JUMP = 3; - public static final byte SOUND_BREAK = 4; - public static final byte SOUND_PLACE = 5; - public static final byte SOUND_HEAVY_STEP = 6; - public static final byte SOUND_GALLOP = 7; - public static final byte SOUND_FALL = 8; - public static final byte SOUND_AMBIENT = 9; - public static final byte SOUND_AMBIENT_BABY = 10; - public static final byte SOUND_AMBIENT_IN_WATER = 11; - public static final byte SOUND_BREATHE = 12; - public static final byte SOUND_DEATH = 13; - public static final byte SOUND_DEATH_IN_WATER = 14; - public static final byte SOUND_DEATH_TO_ZOMBIE = 15; - public static final byte SOUND_HURT = 16; - public static final byte SOUND_HURT_IN_WATER = 17; - public static final byte SOUND_MAD = 18; - public static final byte SOUND_BOOST = 19; - public static final byte SOUND_BOW = 20; - public static final byte SOUND_SQUISH_BIG = 21; - public static final byte SOUND_SQUISH_SMALL = 22; - public static final byte SOUND_FALL_BIG = 23; - public static final byte SOUND_FALL_SMALL = 24; - public static final byte SOUND_SPLASH = 25; - public static final byte SOUND_FIZZ = 26; - public static final byte SOUND_FLAP = 27; - public static final byte SOUND_SWIM = 28; - public static final byte SOUND_DRINK = 29; - public static final byte SOUND_EAT = 30; - public static final byte SOUND_TAKEOFF = 31; - public static final byte SOUND_SHAKE = 32; - public static final byte SOUND_PLOP = 33; - public static final byte SOUND_LAND = 34; - public static final byte SOUND_SADDLE = 35; - public static final byte SOUND_ARMOR = 36; - public static final byte SOUND_ADD_CHEST = 37; - public static final byte SOUND_THROW = 38; - public static final byte SOUND_ATTACK = 39; - public static final byte SOUND_ATTACK_NODAMAGE = 40; - public static final byte SOUND_WARN = 41; - public static final byte SOUND_SHEAR = 42; - public static final byte SOUND_MILK = 43; - public static final byte SOUND_THUNDER = 44; - public static final byte SOUND_EXPLODE = 45; - public static final byte SOUND_FIRE = 46; - public static final byte SOUND_IGNITE = 47; - public static final byte SOUND_FUSE = 48; - public static final byte SOUND_STARE = 49; - public static final byte SOUND_SPAWN = 50; - public static final byte SOUND_SHOOT = 51; - public static final byte SOUND_BREAK_BLOCK = 52; - public static final byte SOUND_REMEDY = 53; - public static final byte SOUND_UNFECT = 54; - public static final byte SOUND_LEVELUP = 55; - public static final byte SOUND_BOW_HIT = 56; - public static final byte SOUND_BULLET_HIT = 57; - public static final byte SOUND_EXTINGUISH_FIRE = 58; - public static final byte SOUND_ITEM_FIZZ = 59; - public static final byte SOUND_CHEST_OPEN = 60; - public static final byte SOUND_CHEST_CLOSED = 61; - public static final byte SOUND_SHULKERBOX_OPEN = 62; - public static final byte SOUND_SHULKERBOX_CLOSED = 63; - public static final byte SOUND_POWER_ON = 64; - public static final byte SOUND_POWER_OFF = 65; - public static final byte SOUND_ATTACH = 66; - public static final byte SOUND_DETACH = 67; - public static final byte SOUND_DENY = 68; - public static final byte SOUND_TRIPOD = 69; - public static final byte SOUND_POP = 70; - public static final byte SOUND_DROP_SLOT = 71; - public static final byte SOUND_NOTE = 72; - public static final byte SOUND_THORNS = 73; - public static final byte SOUND_PISTON_IN = 74; - public static final byte SOUND_PISTON_OUT = 75; - public static final byte SOUND_PORTAL = 76; - public static final byte SOUND_WATER = 77; - public static final byte SOUND_LAVA_POP = 78; - public static final byte SOUND_LAVA = 79; - public static final byte SOUND_BURP = 80; - public static final byte SOUND_BUCKET_FILL_WATER = 81; - public static final byte SOUND_BUCKET_FILL_LAVA = 82; - public static final byte SOUND_BUCKET_EMPTY_WATER = 83; - public static final byte SOUND_BUCKET_EMPTY_LAVA = 84; - public static final byte SOUND_GUARDIAN_FLOP = 85; - public static final byte SOUND_ELDERGUARDIAN_CURSE = 86; - public static final byte SOUND_MOB_WARNING = 87; - public static final byte SOUND_MOB_WARNING_BABY = 88; - public static final byte SOUND_TELEPORT = 89; - public static final byte SOUND_SHULKER_OPEN = 90; - public static final byte SOUND_SHULKER_CLOSE = 91; - public static final byte SOUND_HAGGLE = 92; - public static final byte SOUND_HAGGLE_YES = 93; - public static final byte SOUND_HAGGLE_NO = 94; - public static final byte SOUND_HAGGLE_IDLE = 95; - public static final byte SOUND_CHORUSGROW = 96; - public static final byte SOUND_CHORUSDEATH = 97; - public static final byte SOUND_GLASS = 98; - public static final byte SOUND_CAST_SPELL = 99; - public static final byte SOUND_PREPARE_ATTACK = 100; - public static final byte SOUND_PREPARE_SUMMON = 101; - public static final byte SOUND_PREPARE_WOLOLO = 102; - public static final byte SOUND_FANG = 103; - public static final byte SOUND_CHARGE = 104; - public static final byte SOUND_CAMERA_TAKE_PICTURE = 105; - public static final byte SOUND_DEFAULT = 106; - public static final byte SOUND_UNDEFINED = 107; + public static final int SOUND_ITEM_USE_ON = 0; + public static final int SOUND_HIT = 1; + public static final int SOUND_STEP = 2; + public static final int SOUND_FLY = 3; + public static final int SOUND_JUMP = 4; + public static final int SOUND_BREAK = 5; + public static final int SOUND_PLACE = 6; + public static final int SOUND_HEAVY_STEP = 7; + public static final int SOUND_GALLOP = 8; + public static final int SOUND_FALL = 9; + public static final int SOUND_AMBIENT = 10; + public static final int SOUND_AMBIENT_BABY = 11; + public static final int SOUND_AMBIENT_IN_WATER = 12; + public static final int SOUND_BREATHE = 13; + public static final int SOUND_DEATH = 14; + public static final int SOUND_DEATH_IN_WATER = 15; + public static final int SOUND_DEATH_TO_ZOMBIE = 16; + public static final int SOUND_HURT = 17; + public static final int SOUND_HURT_IN_WATER = 18; + public static final int SOUND_MAD = 19; + public static final int SOUND_BOOST = 20; + public static final int SOUND_BOW = 21; + public static final int SOUND_SQUISH_BIG = 22; + public static final int SOUND_SQUISH_SMALL = 23; + public static final int SOUND_FALL_BIG = 24; + public static final int SOUND_FALL_SMALL = 25; + public static final int SOUND_SPLASH = 26; + public static final int SOUND_FIZZ = 27; + public static final int SOUND_FLAP = 28; + public static final int SOUND_SWIM = 29; + public static final int SOUND_DRINK = 30; + public static final int SOUND_EAT = 31; + public static final int SOUND_TAKEOFF = 32; + public static final int SOUND_SHAKE = 33; + public static final int SOUND_PLOP = 34; + public static final int SOUND_LAND = 35; + public static final int SOUND_SADDLE = 36; + public static final int SOUND_ARMOR = 37; + public static final int SOUND_ADD_CHEST = 38; + public static final int SOUND_THROW = 39; + public static final int SOUND_ATTACK = 40; + public static final int SOUND_ATTACK_NODAMAGE = 41; + public static final int SOUND_WARN = 42; + public static final int SOUND_SHEAR = 43; + public static final int SOUND_MILK = 44; + public static final int SOUND_THUNDER = 45; + public static final int SOUND_EXPLODE = 46; + public static final int SOUND_FIRE = 47; + public static final int SOUND_IGNITE = 48; + public static final int SOUND_FUSE = 49; + public static final int SOUND_STARE = 50; + public static final int SOUND_SPAWN = 51; + public static final int SOUND_SHOOT = 52; + public static final int SOUND_BREAK_BLOCK = 53; + public static final int SOUND_LAUNCH = 54; + public static final int SOUND_BLAST = 55; + public static final int SOUND_LARGE_BLAST = 56; + public static final int SOUND_TWINKLE = 57; + public static final int SOUND_REMEDY = 58; + public static final int SOUND_UNFECT = 59; + public static final int SOUND_LEVELUP = 60; + public static final int SOUND_BOW_HIT = 61; + public static final int SOUND_BULLET_HIT = 62; + public static final int SOUND_EXTINGUISH_FIRE = 63; + public static final int SOUND_ITEM_FIZZ = 64; + public static final int SOUND_CHEST_OPEN = 65; + public static final int SOUND_CHEST_CLOSED = 66; + public static final int SOUND_SHULKERBOX_OPEN = 67; + public static final int SOUND_SHULKERBOX_CLOSED = 68; + public static final int SOUND_POWER_ON = 69; + public static final int SOUND_POWER_OFF = 70; + public static final int SOUND_ATTACH = 71; + public static final int SOUND_DETACH = 72; + public static final int SOUND_DENY = 73; + public static final int SOUND_TRIPOD = 74; + public static final int SOUND_POP = 75; + public static final int SOUND_DROP_SLOT = 76; + public static final int SOUND_NOTE = 77; + public static final int SOUND_THORNS = 78; + public static final int SOUND_PISTON_IN = 79; + public static final int SOUND_PISTON_OUT = 80; + public static final int SOUND_PORTAL = 81; + public static final int SOUND_WATER = 82; + public static final int SOUND_LAVA_POP = 83; + public static final int SOUND_LAVA = 84; + public static final int SOUND_BURP = 85; + public static final int SOUND_BUCKET_FILL_WATER = 86; + public static final int SOUND_BUCKET_FILL_LAVA = 87; + public static final int SOUND_BUCKET_EMPTY_WATER = 88; + public static final int SOUND_BUCKET_EMPTY_LAVA = 89; + public static final int SOUND_RECORD_13 = 90; + public static final int SOUND_RECORD_CAT = 91; + public static final int SOUND_RECORD_BLOCKS = 92; + public static final int SOUND_RECORD_CHIRP = 93; + public static final int SOUND_RECORD_FAR = 94; + public static final int SOUND_RECORD_MALL = 95; + public static final int SOUND_RECORD_MELLOHI = 96; + public static final int SOUND_RECORD_STAL = 97; + public static final int SOUND_RECORD_STRAD = 98; + public static final int SOUND_RECORD_WARD = 99; + public static final int SOUND_RECORD_11 = 100; + public static final int SOUND_RECORD_WAIT = 101; + public static final int SOUND_GUARDIAN_FLOP = 103; + public static final int SOUND_ELDERGUARDIAN_CURSE = 104; + public static final int SOUND_MOB_WARNING = 105; + public static final int SOUND_MOB_WARNING_BABY = 106; + public static final int SOUND_TELEPORT = 107; + public static final int SOUND_SHULKER_OPEN = 108; + public static final int SOUND_SHULKER_CLOSE = 109; + public static final int SOUND_HAGGLE = 110; + public static final int SOUND_HAGGLE_YES = 111; + public static final int SOUND_HAGGLE_NO = 112; + public static final int SOUND_HAGGLE_IDLE = 113; + public static final int SOUND_CHORUSGROW = 114; + public static final int SOUND_CHORUSDEATH = 115; + public static final int SOUND_GLASS = 116; + public static final int SOUND_CAST_SPELL = 117; + public static final int SOUND_PREPARE_ATTACK = 118; + public static final int SOUND_PREPARE_SUMMON = 119; + public static final int SOUND_PREPARE_WOLOLO = 120; + public static final int SOUND_FANG = 121; + public static final int SOUND_CHARGE = 122; + public static final int SOUND_CAMERA_TAKE_PICTURE = 123; + public static final int SOUND_LEASHKNOT_PLACE = 124; + public static final int SOUND_LEASHKNOT_BREAK = 125; + public static final int SOUND_GROWL = 126; + public static final int SOUND_WHINE = 127; + public static final int SOUND_PANT = 128; + public static final int SOUND_PURR = 129; + public static final int SOUND_PURREOW = 130; + public static final int SOUND_DEATH_MIN_VOLUME = 131; + public static final int SOUND_DEATH_MID_VOLUME = 132; + public static final int SOUND_IMITATE_BLAZE = 133; + public static final int SOUND_IMITATE_CAVE_SPIDER = 134; + public static final int SOUND_IMITATE_CREEPER = 135; + public static final int SOUND_IMITATE_ELDER_GUARDIAN = 136; + public static final int SOUND_IMITATE_ENDER_DRAGON = 137; + public static final int SOUND_IMITATE_ENDERMAN = 138; + public static final int SOUND_IMITATE_EVOCATION_ILLAGER = 140; + public static final int SOUND_IMITATE_GHAST = 141; + public static final int SOUND_IMITATE_HUSK = 142; + public static final int SOUND_IMITATE_ILLUSION_ILLAGER = 143; + public static final int SOUND_IMITATE_MAGMA_CUBE = 144; + public static final int SOUND_IMITATE_POLAR_BEAR = 145; + public static final int SOUND_IMITATE_SHULKER = 146; + public static final int SOUND_IMITATE_SILVERFISH = 147; + public static final int SOUND_IMITATE_SKELETON = 148; + public static final int SOUND_IMITATE_SLIME = 149; + public static final int SOUND_IMITATE_SPIDER = 150; + public static final int SOUND_IMITATE_STRAY = 151; + public static final int SOUND_IMITATE_VEX = 152; + public static final int SOUND_IMITATE_VINDICATION_ILLAGER = 153; + public static final int SOUND_IMITATE_WITCH = 154; + public static final int SOUND_IMITATE_WITHER = 155; + public static final int SOUND_IMITATE_WITHER_SKELETON = 156; + public static final int SOUND_IMITATE_WOLF = 157; + public static final int SOUND_IMITATE_ZOMBIE = 158; + public static final int SOUND_IMITATE_ZOMBIE_PIGMAN = 159; + public static final int SOUND_IMITATE_ZOMBIE_VILLAGER = 160; + public static final int SOUND_DEFAULT = 161; + public static final int SOUND_UNDEFINED = 162; public int sound; public float x; public float y; public float z; - public int extraData = -1; - public int pitch = 1; - public boolean unknownBool; - public boolean disableRelativeVolume; + public int extraData = -1; //TODO: Check name + public int pitch = 1; //TODO: Check name + public boolean isBabyMob; + public boolean isGlobal; @Override public void decode() { @@ -133,8 +186,8 @@ public void decode() { this.z = v.z; this.extraData = this.getVarInt(); this.pitch = this.getVarInt(); - this.unknownBool = this.getBoolean(); - this.disableRelativeVolume = this.getBoolean(); + this.isBabyMob = this.getBoolean(); + this.isGlobal = this.getBoolean(); } @Override @@ -144,8 +197,8 @@ public void encode() { this.putVector3f(this.x, this.y, this.z); this.putVarInt(this.extraData); this.putVarInt(this.pitch); - this.putBoolean(this.unknownBool); - this.putBoolean(this.disableRelativeVolume); + this.putBoolean(this.isBabyMob); + this.putBoolean(this.isGlobal); } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/LoginPacket.java b/src/main/java/cn/nukkit/network/protocol/LoginPacket.java index 7290922b85..c1fab370b2 100644 --- a/src/main/java/cn/nukkit/network/protocol/LoginPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/LoginPacket.java @@ -21,11 +21,14 @@ public class LoginPacket extends DataPacket { public String username; public int protocol; - public byte gameEdition; public UUID clientUUID; public long clientId; public Skin skin; + public String skinGeometryName; + public byte[] skinGeometry; + + public byte[] capeData; @Override public byte pid() { @@ -35,7 +38,6 @@ public byte pid() { @Override public void decode() { this.protocol = this.getInt(); - this.gameEdition = (byte) this.getByte(); this.setBuffer(this.getByteArray(), 0); decodeChainData(); decodeSkinData(); @@ -72,7 +74,16 @@ private void decodeSkinData() { String skinId = null; if (skinToken.has("ClientRandomId")) this.clientId = skinToken.get("ClientRandomId").getAsLong(); if (skinToken.has("SkinId")) skinId = skinToken.get("SkinId").getAsString(); - if (skinToken.has("SkinData")) this.skin = new Skin(skinToken.get("SkinData").getAsString(), skinId); + if (skinToken.has("SkinData")) { + this.skin = new Skin(skinToken.get("SkinData").getAsString(), skinId); + + if (skinToken.has("CapeData")) + this.skin.setCape(this.skin.new Cape(Base64.getDecoder().decode(skinToken.get("CapeData").getAsString()))); + } + + if (skinToken.has("SkinGeometryName")) this.skinGeometryName = skinToken.get("SkinGeometryName").getAsString(); + if (skinToken.has("SkinGeometry")) + this.skinGeometry = Base64.getDecoder().decode(skinToken.get("SkinGeometry").getAsString()); } private JsonObject decodeToken(String token) { diff --git a/src/main/java/cn/nukkit/network/protocol/MapInfoRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/MapInfoRequestPacket.java index 0edf1e43f8..f28d1a46c6 100644 --- a/src/main/java/cn/nukkit/network/protocol/MapInfoRequestPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/MapInfoRequestPacket.java @@ -13,7 +13,7 @@ public byte pid() { @Override public void decode() { - mapId = this.getVarLong(); + mapId = this.getEntityUniqueId(); } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/MobArmorEquipmentPacket.java b/src/main/java/cn/nukkit/network/protocol/MobArmorEquipmentPacket.java index fa26b06c87..b34c6fc013 100644 --- a/src/main/java/cn/nukkit/network/protocol/MobArmorEquipmentPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/MobArmorEquipmentPacket.java @@ -19,7 +19,7 @@ public byte pid() { @Override public void decode() { - this.eid = this.getVarLong(); + this.eid = this.getEntityRuntimeId(); this.slots = new Item[4]; this.slots[0] = this.getSlot(); this.slots[1] = this.getSlot(); @@ -30,7 +30,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityRuntimeId(this.eid); this.putSlot(this.slots[0]); this.putSlot(this.slots[1]); this.putSlot(this.slots[2]); diff --git a/src/main/java/cn/nukkit/network/protocol/MobEffectPacket.java b/src/main/java/cn/nukkit/network/protocol/MobEffectPacket.java index afa89f0f5d..c04a3f23ef 100644 --- a/src/main/java/cn/nukkit/network/protocol/MobEffectPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/MobEffectPacket.java @@ -32,7 +32,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityRuntimeId(this.eid); this.putByte((byte) this.eventId); this.putVarInt(this.effectId); this.putVarInt(this.amplifier); diff --git a/src/main/java/cn/nukkit/network/protocol/MobEquipmentPacket.java b/src/main/java/cn/nukkit/network/protocol/MobEquipmentPacket.java index f1ea1ebd50..22c0033d1e 100644 --- a/src/main/java/cn/nukkit/network/protocol/MobEquipmentPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/MobEquipmentPacket.java @@ -16,26 +16,26 @@ public byte pid() { public long eid; public Item item; - public int slot; - public int selectedSlot; + public int inventorySlot; + public int hotbarSlot; public int windowId; @Override public void decode() { - this.eid = this.getVarLong(); //EntityRuntimeID + this.eid = this.getEntityRuntimeId(); //EntityRuntimeID this.item = this.getSlot(); - this.slot = this.getByte(); - this.selectedSlot = this.getByte(); + this.inventorySlot = this.getByte(); + this.hotbarSlot = this.getByte(); this.windowId = this.getByte(); } @Override public void encode() { this.reset(); - this.putVarLong(this.eid); //EntityRuntimeID + this.putEntityRuntimeId(this.eid); //EntityRuntimeID this.putSlot(this.item); - this.putByte((byte) this.slot); - this.putByte((byte) this.selectedSlot); + this.putByte((byte) this.inventorySlot); + this.putByte((byte) this.hotbarSlot); this.putByte((byte) this.windowId); } } diff --git a/src/main/java/cn/nukkit/network/protocol/ModalFormRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/ModalFormRequestPacket.java new file mode 100644 index 0000000000..20418c820d --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ModalFormRequestPacket.java @@ -0,0 +1,24 @@ +package cn.nukkit.network.protocol; + +public class ModalFormRequestPacket extends DataPacket { + + public int formId; + public String data; + + @Override + public byte pid() { + return ProtocolInfo.MODAL_FORM_REQUEST_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + this.reset(); + this.putVarInt(this.formId); + this.putString(this.data); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ModalFormResponsePacket.java b/src/main/java/cn/nukkit/network/protocol/ModalFormResponsePacket.java new file mode 100644 index 0000000000..a17743b136 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ModalFormResponsePacket.java @@ -0,0 +1,23 @@ +package cn.nukkit.network.protocol; + +public class ModalFormResponsePacket extends DataPacket { + + public int formId; + public String data; + + @Override + public byte pid() { + return ProtocolInfo.MODAL_FORM_RESPONSE_PACKET; + } + + @Override + public void decode() { + this.formId = this.getVarInt(); + this.data = this.getString(); //Data will be null if player close form without submit (by cross button or ESC) + } + + @Override + public void encode() { + + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/MoveEntityPacket.java b/src/main/java/cn/nukkit/network/protocol/MoveEntityPacket.java index 5ff8ba1f0d..9fef170c0f 100644 --- a/src/main/java/cn/nukkit/network/protocol/MoveEntityPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/MoveEntityPacket.java @@ -26,7 +26,7 @@ public byte pid() { @Override public void decode() { - this.eid = this.getVarLong(); + this.eid = this.getEntityRuntimeId(); Vector3f v = this.getVector3f(); this.x = v.x; this.y = v.y; @@ -41,7 +41,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityRuntimeId(this.eid); this.putVector3f((float) this.x, (float) this.y, (float) this.z); this.putByte((byte) (this.pitch / (360d / 256d))); this.putByte((byte) (this.headYaw / (360d / 256d))); diff --git a/src/main/java/cn/nukkit/network/protocol/MovePlayerPacket.java b/src/main/java/cn/nukkit/network/protocol/MovePlayerPacket.java index 1745370746..41e11ec247 100644 --- a/src/main/java/cn/nukkit/network/protocol/MovePlayerPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/MovePlayerPacket.java @@ -9,10 +9,10 @@ public class MovePlayerPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.MOVE_PLAYER_PACKET; - public static final byte MODE_NORMAL = 0; - public static final byte MODE_RESET = 1; - public static final byte MODE_TELEPORT = 2; - public static final byte MODE_PITCH = 3; //facepalm Mojang + public static final int MODE_NORMAL = 0; + public static final int MODE_RESET = 1; + public static final int MODE_TELEPORT = 2; + public static final int MODE_PITCH = 3; //facepalm Mojang public long eid; public float x; @@ -21,7 +21,7 @@ public class MovePlayerPacket extends DataPacket { public float yaw; public float headYaw; public float pitch; - public byte mode = MODE_NORMAL; + public int mode = MODE_NORMAL; public boolean onGround; public long ridingEid; public int int1 = 0; @@ -29,7 +29,7 @@ public class MovePlayerPacket extends DataPacket { @Override public void decode() { - this.eid = this.getVarLong(); + this.eid = this.getEntityRuntimeId(); Vector3f v = this.getVector3f(); this.x = v.x; this.y = v.y; @@ -37,10 +37,10 @@ public void decode() { this.pitch = this.getLFloat(); this.headYaw = this.getLFloat(); this.yaw = this.getLFloat(); - this.mode = (byte) this.getByte(); + this.mode = this.getByte(); this.onGround = this.getBoolean(); - this.ridingEid = this.getVarLong(); - if (this.mode == MODE_TELEPORT){ + this.ridingEid = this.getEntityRuntimeId(); + if (this.mode == MODE_TELEPORT) { this.int1 = this.getLInt(); this.int2 = this.getLInt(); } @@ -49,15 +49,15 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityRuntimeId(this.eid); this.putVector3f(this.x, this.y, this.z); this.putLFloat(this.pitch); this.putLFloat(this.yaw); this.putLFloat(this.headYaw); - this.putByte(this.mode); + this.putByte((byte) this.mode); this.putBoolean(this.onGround); - this.putVarLong(this.ridingEid); - if (this.mode == MODE_TELEPORT){ + this.putEntityRuntimeId(this.ridingEid); + if (this.mode == MODE_TELEPORT) { this.putLInt(this.int1); this.putLInt(this.int2); } diff --git a/src/main/java/cn/nukkit/network/protocol/NPCRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/NPCRequestPacket.java new file mode 100644 index 0000000000..99e79e9a10 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/NPCRequestPacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class NPCRequestPacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.NPC_REQUEST_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/PlaySoundPacket.java b/src/main/java/cn/nukkit/network/protocol/PlaySoundPacket.java index aa0106e6e4..f8b131f453 100644 --- a/src/main/java/cn/nukkit/network/protocol/PlaySoundPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/PlaySoundPacket.java @@ -23,8 +23,9 @@ public void decode() { @Override public void encode() { + this.reset(); this.putString(this.name); - this.putBlockCoords(this.x, this.y, this.z); + this.putBlockVector3(this.x * 8, this.y * 8, this.z * 8); this.putLFloat(this.volume); this.putLFloat(this.pitch); } diff --git a/src/main/java/cn/nukkit/network/protocol/PlayerActionPacket.java b/src/main/java/cn/nukkit/network/protocol/PlayerActionPacket.java index bcc6de31d8..cab869e93b 100644 --- a/src/main/java/cn/nukkit/network/protocol/PlayerActionPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/PlayerActionPacket.java @@ -9,24 +9,25 @@ public class PlayerActionPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.PLAYER_ACTION_PACKET; - public static final byte ACTION_START_BREAK = 0; - public static final byte ACTION_ABORT_BREAK = 1; - public static final byte ACTION_STOP_BREAK = 2; - - public static final byte ACTION_RELEASE_ITEM = 5; - public static final byte ACTION_STOP_SLEEPING = 6; - public static final byte ACTION_RESPAWN = 7; - public static final byte ACTION_JUMP = 8; - public static final byte ACTION_START_SPRINT = 9; - public static final byte ACTION_STOP_SPRINT = 10; - public static final byte ACTION_START_SNEAK = 11; - public static final byte ACTION_STOP_SNEAK = 12; - public static final byte ACTION_DIMENSION_CHANGE = 13; - public static final byte ACTION_ABORT_DIMENSION_CHANGE = 14; - public static final byte ACTION_START_GLIDE = 15; - public static final byte ACTION_STOP_GLIDE = 16; - public static final byte ACTION_WORLD_IMMUTABLE = 17; - public static final byte ACTION_CONTINUE_BREAK = 18; + public static final int ACTION_START_BREAK = 0; + public static final int ACTION_ABORT_BREAK = 1; + public static final int ACTION_STOP_BREAK = 2; + public static final int ACTION_GET_UPDATED_BLOCK = 3; + public static final int ACTION_DROP_ITEM = 4; + public static final int ACTION_START_SLEEPING = 5; + public static final int ACTION_STOP_SLEEPING = 6; + public static final int ACTION_RESPAWN = 7; + public static final int ACTION_JUMP = 8; + public static final int ACTION_START_SPRINT = 9; + public static final int ACTION_STOP_SPRINT = 10; + public static final int ACTION_START_SNEAK = 11; + public static final int ACTION_STOP_SNEAK = 12; + public static final int ACTION_DIMENSION_CHANGE_REQUEST = 13; //sent when dying in different dimension + public static final int ACTION_DIMENSION_CHANGE_ACK = 14; //sent when spawning in a different dimension to tell the server we spawned + public static final int ACTION_START_GLIDE = 15; + public static final int ACTION_STOP_GLIDE = 16; + public static final int ACTION_BUILD_DENIED = 17; + public static final int ACTION_CONTINUE_BREAK = 18; public long entityId; public int action; @@ -38,9 +39,9 @@ public class PlayerActionPacket extends DataPacket { @Override public void decode() { - this.entityId = this.getVarLong(); + this.entityId = this.getEntityRuntimeId(); this.action = this.getVarInt(); - BlockVector3 v = this.getBlockCoords(); + BlockVector3 v = this.getBlockVector3(); this.x = v.x; this.y = v.y; this.z = v.z; @@ -50,9 +51,9 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.entityId); + this.putEntityRuntimeId(this.entityId); this.putVarInt(this.action); - this.putBlockCoords(this.x, this.y, this.z); + this.putBlockVector3(this.x, this.y, this.z); this.putVarInt(this.face); } diff --git a/src/main/java/cn/nukkit/network/protocol/PlayerHotbarPacket.java b/src/main/java/cn/nukkit/network/protocol/PlayerHotbarPacket.java new file mode 100644 index 0000000000..0dc249f454 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/PlayerHotbarPacket.java @@ -0,0 +1,45 @@ +package cn.nukkit.network.protocol; + +import cn.nukkit.network.protocol.types.ContainerIds; +import cn.nukkit.utils.Binary; + +public class PlayerHotbarPacket extends DataPacket { + + public int selectedHotbarSlot; + public int windowId = ContainerIds.INVENTORY; + + public int[] slots; + + public boolean selectHotbarSlot = true; + + @Override + public byte pid() { + return ProtocolInfo.PLAYER_HOTBAR_PACKET; + } + + @Override + public void decode() { + this.selectedHotbarSlot = (int) this.getUnsignedVarInt(); + this.windowId = this.getByte(); + int count = (int) this.getUnsignedVarInt(); + slots = new int[count]; + + for (int i = 0; i < count; ++i) { + this.slots[i] = Binary.signInt((int) this.getUnsignedVarInt()); + } + this.selectHotbarSlot = this.getBoolean(); + } + + @Override + public void encode() { + this.reset(); + this.putUnsignedVarInt(this.selectedHotbarSlot); + this.putByte((byte) this.windowId); + this.putUnsignedVarInt(this.slots.length); + for (int i : slots) { + this.putUnsignedVarInt(i); + } + + this.putBoolean(this.selectHotbarSlot); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/PlayerListPacket.java b/src/main/java/cn/nukkit/network/protocol/PlayerListPacket.java index 09bb760ce8..26d9a5cf5d 100644 --- a/src/main/java/cn/nukkit/network/protocol/PlayerListPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/PlayerListPacket.java @@ -33,6 +33,10 @@ public void encode() { this.putVarLong(entry.entityId); this.putString(entry.name); this.putSkin(entry.skin); + this.putByteArray(entry.skin.getCape().getData()); + this.putString(entry.geometryModel); + this.putByteArray(entry.geometryData); + this.putString(entry.xboxUserId); } else { this.putUUID(entry.uuid); } @@ -51,16 +55,26 @@ public static class Entry { public long entityId = 0; public String name = ""; public Skin skin; + public byte[] capeData = new byte[0]; //TODO + public String geometryModel = ""; + public byte[] geometryData = new byte[0]; //TODO + public String xboxUserId = ""; //TODO public Entry(UUID uuid) { this.uuid = uuid; } public Entry(UUID uuid, long entityId, String name, Skin skin) { + this(uuid, entityId, name, skin, ""); + } + + public Entry(UUID uuid, long entityId, String name, Skin skin, String xboxUserId) { this.uuid = uuid; this.entityId = entityId; this.name = name; this.skin = skin; + this.capeData = skin.getCape().getData(); + this.xboxUserId = xboxUserId == null ? "" : xboxUserId; } } diff --git a/src/main/java/cn/nukkit/network/protocol/PlayerSkinPacket.java b/src/main/java/cn/nukkit/network/protocol/PlayerSkinPacket.java new file mode 100644 index 0000000000..b7de833ab5 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/PlayerSkinPacket.java @@ -0,0 +1,49 @@ +package cn.nukkit.network.protocol; + +import cn.nukkit.entity.data.Skin; + +import java.util.UUID; + +public class PlayerSkinPacket extends DataPacket { + + public UUID uuid; + public Skin skin; + public String skinName; + public String serializeName; + public String geometryModel; + public String geometryData; + + @Override + public byte pid() { + return ProtocolInfo.PLAYER_SKIN_PACKET; + } + + @Override + public void decode() { + this.uuid = this.getUUID(); + String skinId = this.getString(); + this.skinName = this.getString(); + this.serializeName = this.getString(); + byte[] data = this.getByteArray(); + byte[] cape = this.getByteArray(); + + this.skin = new Skin(data, skinId); + this.skin.setCape(this.skin.new Cape(cape)); + + this.geometryModel = this.getString(); + this.geometryData = this.getString(); + } + + @Override + public void encode() { + this.reset(); + this.putUUID(this.uuid); + this.putString(this.skin.getModel()); + this.putString(this.skinName); + this.putString(this.serializeName); + this.putByteArray(this.skin.getData()); + this.putByteArray(this.skin.getCape().getData()); + this.putString(this.geometryModel); + this.putString(this.geometryData); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java b/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java index 5626c4fcc4..1a1238f5e4 100644 --- a/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java +++ b/src/main/java/cn/nukkit/network/protocol/ProtocolInfo.java @@ -9,10 +9,10 @@ public interface ProtocolInfo { /** * Actual Minecraft: PE protocol version */ - byte CURRENT_PROTOCOL = Integer.valueOf("113").byteValue(); //plugins can change it + int CURRENT_PROTOCOL = Integer.valueOf("137"); //plugins can change it - String MINECRAFT_VERSION = "v1.1.3"; - String MINECRAFT_VERSION_NETWORK = "1.1.3"; + String MINECRAFT_VERSION = "v1.2.2"; + String MINECRAFT_VERSION_NETWORK = "1.2.2"; byte LOGIN_PACKET = 0x01; byte PLAY_STATUS_PACKET = 0x02; @@ -34,21 +34,21 @@ public interface ProtocolInfo { byte MOVE_ENTITY_PACKET = 0x12; byte MOVE_PLAYER_PACKET = 0x13; byte RIDER_JUMP_PACKET = 0x14; - byte REMOVE_BLOCK_PACKET = 0x15; - byte UPDATE_BLOCK_PACKET = 0x16; - byte ADD_PAINTING_PACKET = 0x17; - byte EXPLODE_PACKET = 0x18; - byte LEVEL_SOUND_EVENT_PACKET = 0x19; - byte LEVEL_EVENT_PACKET = 0x1a; - byte BLOCK_EVENT_PACKET = 0x1b; - byte ENTITY_EVENT_PACKET = 0x1c; - byte MOB_EFFECT_PACKET = 0x1d; - byte UPDATE_ATTRIBUTES_PACKET = 0x1e; + byte UPDATE_BLOCK_PACKET = 0x15; + byte ADD_PAINTING_PACKET = 0x16; + byte EXPLODE_PACKET = 0x17; + byte LEVEL_SOUND_EVENT_PACKET = 0x18; + byte LEVEL_EVENT_PACKET = 0x19; + byte BLOCK_EVENT_PACKET = 0x1a; + byte ENTITY_EVENT_PACKET = 0x1b; + byte MOB_EFFECT_PACKET = 0x1c; + byte UPDATE_ATTRIBUTES_PACKET = 0x1d; + byte INVENTORY_TRANSACTION_PACKET = 0x1e; byte MOB_EQUIPMENT_PACKET = 0x1f; byte MOB_ARMOR_EQUIPMENT_PACKET = 0x20; byte INTERACT_PACKET = 0x21; byte BLOCK_PICK_REQUEST_PACKET = 0x22; - byte USE_ITEM_PACKET = 0x23; + byte ENTITY_PICK_REQUEST_PACKET = 0x23; byte PLAYER_ACTION_PACKET = 0x24; byte ENTITY_FALL_PACKET = 0x25; byte HURT_ARMOR_PACKET = 0x26; @@ -59,15 +59,15 @@ public interface ProtocolInfo { byte SET_SPAWN_POSITION_PACKET = 0x2b; byte ANIMATE_PACKET = 0x2c; byte RESPAWN_PACKET = 0x2d; - byte DROP_ITEM_PACKET = 0x2e; - byte INVENTORY_ACTION_PACKET = 0x2f; - byte CONTAINER_OPEN_PACKET = 0x30; - byte CONTAINER_CLOSE_PACKET = 0x31; - byte CONTAINER_SET_SLOT_PACKET = 0x32; + byte CONTAINER_OPEN_PACKET = 0x2e; + byte CONTAINER_CLOSE_PACKET = 0x2f; + byte PLAYER_HOTBAR_PACKET = 0x30; + byte INVENTORY_CONTENT_PACKET = 0x31; + byte INVENTORY_SLOT_PACKET = 0x32; byte CONTAINER_SET_DATA_PACKET = 0x33; - byte CONTAINER_SET_CONTENT_PACKET = 0x34; - byte CRAFTING_DATA_PACKET = 0x35; - byte CRAFTING_EVENT_PACKET = 0x36; + byte CRAFTING_DATA_PACKET = 0x34; + byte CRAFTING_EVENT_PACKET = 0x35; + byte GUI_DATA_PICK_ITEM_PACKET = 0x36; byte ADVENTURE_SETTINGS_PACKET = 0x37; byte BLOCK_ENTITY_DATA_PACKET = 0x38; byte PLAYER_INPUT_PACKET = 0x39; @@ -78,32 +78,46 @@ public interface ProtocolInfo { byte SET_PLAYER_GAME_TYPE_PACKET = 0x3e; byte PLAYER_LIST_PACKET = 0x3f; byte SIMPLE_EVENT_PACKET = 0x40; - byte EVENT_PACKET = 0x41; + byte TELEMETRY_EVENT_PACKET = 0x41; byte SPAWN_EXPERIENCE_ORB_PACKET = 0x42; byte CLIENTBOUND_MAP_ITEM_DATA_PACKET = 0x43; byte MAP_INFO_REQUEST_PACKET = 0x44; byte REQUEST_CHUNK_RADIUS_PACKET = 0x45; byte CHUNK_RADIUS_UPDATED_PACKET = 0x46; byte ITEM_FRAME_DROP_ITEM_PACKET = 0x47; - byte REPLACE_ITEM_IN_SLOT_PACKET = 0x48; - byte GAME_RULES_CHANGED_PACKET = 0x49; - byte CAMERA_PACKET = 0x4a; - byte ADD_ITEM_PACKET = 0x4b; - byte BOSS_EVENT_PACKET = 0x4c; - byte SHOW_CREDITS_PACKET = 0x4d; - byte AVAILABLE_COMMANDS_PACKET = 0x4e; - byte COMMAND_STEP_PACKET = 0x4f; - byte COMMAND_BLOCK_UPDATE_PACKET = 0x50; - byte UPDATE_TRADE_PACKET = 0x51; - byte UPDATE_EQUIP_PACKET = 0x52; - byte RESOURCE_PACK_DATA_INFO_PACKET = 0x53; - byte RESOURCE_PACK_CHUNK_DATA_PACKET = 0x54; - byte RESOURCE_PACK_CHUNK_REQUEST_PACKET = 0x55; - byte TRANSFER_PACKET = 0x56; - byte PLAY_SOUND_PACKET = 0x57; - byte STOP_SOUND_PACKET = 0x58; - byte SET_TITLE_PACKET = 0x59; - byte ADD_BEHAVIOR_TREE_PACKET = 0x5a; - byte STRUCTURE_BLOCK_UPDATE_PACKET = 0x5b; + byte GAME_RULES_CHANGED_PACKET = 0x48; + byte CAMERA_PACKET = 0x49; + byte BOSS_EVENT_PACKET = 0x4a; + byte SHOW_CREDITS_PACKET = 0x4b; + byte AVAILABLE_COMMANDS_PACKET = 0x4c; + byte COMMAND_REQUEST_PACKET = 0x4d; + byte COMMAND_BLOCK_UPDATE_PACKET = 0x4e; + byte COMMAND_OUTPUT_PACKET = 0x4f; + byte UPDATE_TRADE_PACKET = 0x50; + byte UPDATE_EQUIPMENT_PACKET = 0x51; + byte RESOURCE_PACK_DATA_INFO_PACKET = 0x52; + byte RESOURCE_PACK_CHUNK_DATA_PACKET = 0x53; + byte RESOURCE_PACK_CHUNK_REQUEST_PACKET = 0x54; + byte TRANSFER_PACKET = 0x55; + byte PLAY_SOUND_PACKET = 0x56; + byte STOP_SOUND_PACKET = 0x57; + byte SET_TITLE_PACKET = 0x58; + byte ADD_BEHAVIOR_TREE_PACKET = 0x59; + byte STRUCTURE_BLOCK_UPDATE_PACKET = 0x5a; + byte SHOW_STORE_OFFER_PACKET = 0x5b; + byte PURCHASE_RECEIPT_PACKET = 0x5c; + byte PLAYER_SKIN_PACKET = 0x5d; + byte SUB_CLIENT_LOGIN_PACKET = 0x5e; + byte INITIATE_WEB_SOCKET_CONNECTION_PACKET = 0x5f; + byte SET_LAST_HURT_BY_PACKET = 0x60; + byte BOOK_EDIT_PACKET = 0x61; + byte NPC_REQUEST_PACKET = 0x62; + byte PHOTO_TRANSFER_PACKET = 0x63; + byte MODAL_FORM_REQUEST_PACKET = 0x64; + byte MODAL_FORM_RESPONSE_PACKET = 0x65; + byte SERVER_SETTINGS_REQUEST_PACKET = 0x66; + byte SERVER_SETTINGS_RESPONSE_PACKET = 0x67; + byte SHOW_PROFILE_PACKET = 0x68; + byte SET_DEFAULT_GAME_TYPE_PACKET = 0x69; byte BATCH_PACKET = (byte) 0xff; } diff --git a/src/main/java/cn/nukkit/network/protocol/RemoveBlockPacket.java b/src/main/java/cn/nukkit/network/protocol/RemoveBlockPacket.java deleted file mode 100644 index d20f2f1632..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/RemoveBlockPacket.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.math.BlockVector3; - -/** - * @author Nukkit Project Team - */ -public class RemoveBlockPacket extends DataPacket { - - public static final byte NETWORK_ID = ProtocolInfo.REMOVE_BLOCK_PACKET; - - public int x; - public int y; - public int z; - - @Override - public void decode() { - BlockVector3 v = this.getBlockCoords(); - this.x = v.x; - this.y = v.y; - this.z = v.z; - } - - @Override - public void encode() { - } - - @Override - public byte pid() { - return NETWORK_ID; - } - -} diff --git a/src/main/java/cn/nukkit/network/protocol/RemoveEntityPacket.java b/src/main/java/cn/nukkit/network/protocol/RemoveEntityPacket.java index 46cba714f1..1d5ac0dded 100644 --- a/src/main/java/cn/nukkit/network/protocol/RemoveEntityPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/RemoveEntityPacket.java @@ -22,6 +22,6 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityUniqueId(this.eid); } } diff --git a/src/main/java/cn/nukkit/network/protocol/ReplaceItemInSlotPacket.java b/src/main/java/cn/nukkit/network/protocol/ReplaceItemInSlotPacket.java deleted file mode 100644 index a70b68b7e1..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/ReplaceItemInSlotPacket.java +++ /dev/null @@ -1,30 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; - -/** - * Created by Pub4Game on 29.04.2016. - */ -public class ReplaceItemInSlotPacket extends DataPacket { - - public static final byte NETWORK_ID = ProtocolInfo.REPLACE_ITEM_IN_SLOT_PACKET; - - public Item item; - - @Override - public void decode() { - - } - - @Override - public void encode() { - this.reset(); - this.putSlot(this.item); - } - - @Override - public byte pid() { - return NETWORK_ID; - } - -} \ No newline at end of file diff --git a/src/main/java/cn/nukkit/network/protocol/RiderJumpPacket.java b/src/main/java/cn/nukkit/network/protocol/RiderJumpPacket.java index 3ef8d1e88c..86b11887c0 100644 --- a/src/main/java/cn/nukkit/network/protocol/RiderJumpPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/RiderJumpPacket.java @@ -13,11 +13,12 @@ public byte pid() { @Override public void decode() { - + this.unknown = this.getVarInt(); } @Override public void encode() { + this.reset(); this.putVarInt(this.unknown); } } diff --git a/src/main/java/cn/nukkit/network/protocol/ServerSettingsRequestPacket.java b/src/main/java/cn/nukkit/network/protocol/ServerSettingsRequestPacket.java new file mode 100644 index 0000000000..026f7a99e0 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ServerSettingsRequestPacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class ServerSettingsRequestPacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.SERVER_SETTINGS_REQUEST_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ServerSettingsResponsePacket.java b/src/main/java/cn/nukkit/network/protocol/ServerSettingsResponsePacket.java new file mode 100644 index 0000000000..f7efce36dd --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ServerSettingsResponsePacket.java @@ -0,0 +1,24 @@ +package cn.nukkit.network.protocol; + +public class ServerSettingsResponsePacket extends DataPacket { + + public int formId; + public String data; + + @Override + public byte pid() { + return ProtocolInfo.SERVER_SETTINGS_RESPONSE_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + this.reset(); + this.putVarInt(this.formId); + this.putString(this.data); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/ServerToClientHandshakePacket.java b/src/main/java/cn/nukkit/network/protocol/ServerToClientHandshakePacket.java new file mode 100644 index 0000000000..ac887d33e6 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ServerToClientHandshakePacket.java @@ -0,0 +1,23 @@ +package cn.nukkit.network.protocol; + +public class ServerToClientHandshakePacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.SERVER_TO_CLIENT_HANDSHAKE_PACKET; + } + + public String publicKey; + public String serverToken; + public String privateKey; + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/SetEntityDataPacket.java b/src/main/java/cn/nukkit/network/protocol/SetEntityDataPacket.java index f15027cdb7..49e90f1b0e 100644 --- a/src/main/java/cn/nukkit/network/protocol/SetEntityDataPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/SetEntityDataPacket.java @@ -26,7 +26,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityRuntimeId(this.eid); this.put(Binary.writeMetadata(this.metadata)); } } diff --git a/src/main/java/cn/nukkit/network/protocol/SetEntityLinkPacket.java b/src/main/java/cn/nukkit/network/protocol/SetEntityLinkPacket.java index da60c96b78..863d8d41e3 100644 --- a/src/main/java/cn/nukkit/network/protocol/SetEntityLinkPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/SetEntityLinkPacket.java @@ -14,6 +14,7 @@ public class SetEntityLinkPacket extends DataPacket { public long rider; public long riding; public byte type; + public byte unknownByte; @Override public void decode() { @@ -23,14 +24,14 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.rider); - this.putVarLong(this.riding); + this.putEntityUniqueId(this.rider); + this.putEntityUniqueId(this.riding); this.putByte(this.type); + this.putByte(this.unknownByte); } @Override public byte pid() { return NETWORK_ID; } - } diff --git a/src/main/java/cn/nukkit/network/protocol/SetEntityMotionPacket.java b/src/main/java/cn/nukkit/network/protocol/SetEntityMotionPacket.java index 7ee5d898ed..7aa9ae9f09 100644 --- a/src/main/java/cn/nukkit/network/protocol/SetEntityMotionPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/SetEntityMotionPacket.java @@ -25,7 +25,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.eid); + this.putEntityRuntimeId(this.eid); this.putVector3f(this.motionX, this.motionY, this.motionZ); } } diff --git a/src/main/java/cn/nukkit/network/protocol/SetLastHurtByPacket.java b/src/main/java/cn/nukkit/network/protocol/SetLastHurtByPacket.java new file mode 100644 index 0000000000..46001b273a --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/SetLastHurtByPacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class SetLastHurtByPacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.SET_LAST_HURT_BY_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/SetSpawnPositionPacket.java b/src/main/java/cn/nukkit/network/protocol/SetSpawnPositionPacket.java index 1b58639039..a3f4293c64 100644 --- a/src/main/java/cn/nukkit/network/protocol/SetSpawnPositionPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/SetSpawnPositionPacket.java @@ -25,7 +25,7 @@ public void decode() { public void encode() { this.reset(); this.putVarInt(this.spawnType); - this.putBlockCoords(this.x, this.y, this.z); + this.putBlockVector3(this.x, this.y, this.z); this.putBoolean(this.spawnForced); } diff --git a/src/main/java/cn/nukkit/network/protocol/ShowCreditsPacket.java b/src/main/java/cn/nukkit/network/protocol/ShowCreditsPacket.java index 113cb11f0a..8089289499 100644 --- a/src/main/java/cn/nukkit/network/protocol/ShowCreditsPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/ShowCreditsPacket.java @@ -22,7 +22,8 @@ public void decode() { @Override public void encode() { - this.putVarLong(this.eid); + this.reset(); + this.putEntityRuntimeId(this.eid); this.putVarInt(this.status); } } diff --git a/src/main/java/cn/nukkit/network/protocol/ShowProfilePacket.java b/src/main/java/cn/nukkit/network/protocol/ShowProfilePacket.java new file mode 100644 index 0000000000..89c85bdf1a --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/ShowProfilePacket.java @@ -0,0 +1,28 @@ +package cn.nukkit.network.protocol; + +/** + * author: MagicDroidX + * Nukkit Project + */ +public class ShowProfilePacket extends DataPacket { + public static final byte NETWORK_ID = ProtocolInfo.SHOW_PROFILE_PACKET; + + public String xuid; + + @Override + public byte pid() { + return NETWORK_ID; + } + + @Override + public void decode() { + this.xuid = this.getString(); + } + + @Override + public void encode() { + this.reset(); + this.putString(this.xuid); + } + +} diff --git a/src/main/java/cn/nukkit/network/protocol/SimpleEventPacket.java b/src/main/java/cn/nukkit/network/protocol/SimpleEventPacket.java new file mode 100644 index 0000000000..a045ff1243 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/SimpleEventPacket.java @@ -0,0 +1,22 @@ +package cn.nukkit.network.protocol; + +public class SimpleEventPacket extends DataPacket { + + public short unknown; + + @Override + public byte pid() { + return ProtocolInfo.SIMPLE_EVENT_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + this.reset(); + this.putShort(this.unknown); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/StartGamePacket.java b/src/main/java/cn/nukkit/network/protocol/StartGamePacket.java index 5863e5b575..a376b6abe1 100644 --- a/src/main/java/cn/nukkit/network/protocol/StartGamePacket.java +++ b/src/main/java/cn/nukkit/network/protocol/StartGamePacket.java @@ -25,7 +25,7 @@ public byte pid() { public int seed; public byte dimension; public int generator = 1; - public int gamemode; + public int worldGamemode; public int difficulty; public int spawnX; public int spawnY; @@ -35,15 +35,24 @@ public byte pid() { public boolean eduMode = false; public float rainLevel; public float lightningLevel; + public boolean multiplayerGame = true; + public boolean broadcastToLAN = true; + public boolean broadcastToXboxLive = true; public boolean commandsEnabled; public boolean isTexturePacksRequired = false; public RuleData[] ruleDatas = new RuleData[0]; + public boolean bonusChest = false; + public boolean trustPlayers = false; + public int permissionLevel = 1; + public int gamePublish = 4; public String levelId = ""; //base64 string, usually the same as world folder name in vanilla public String worldName; public String premiumWorldTemplateId = ""; public boolean unknown = false; public long currentTick; + public int enchantmentSeed; + @Override public void decode() { @@ -52,8 +61,8 @@ public void decode() { @Override public void encode() { this.reset(); - this.putVarLong(this.entityUniqueId); - this.putVarLong(this.entityRuntimeId); + this.putEntityUniqueId(this.entityUniqueId); + this.putEntityRuntimeId(this.entityRuntimeId); this.putVarInt(this.playerGamemode); this.putVector3f(this.x, this.y, this.z); this.putLFloat(this.yaw); @@ -61,25 +70,33 @@ public void encode() { this.putVarInt(this.seed); this.putVarInt(this.dimension); this.putVarInt(this.generator); - this.putVarInt(this.gamemode); + this.putVarInt(this.worldGamemode); this.putVarInt(this.difficulty); - this.putBlockCoords(this.spawnX, this.spawnY, this.spawnZ); + this.putBlockVector3(this.spawnX, this.spawnY, this.spawnZ); this.putBoolean(this.hasAchievementsDisabled); this.putVarInt(this.dayCycleStopTime); this.putBoolean(this.eduMode); this.putLFloat(this.rainLevel); this.putLFloat(this.lightningLevel); + this.putBoolean(this.multiplayerGame); + this.putBoolean(this.broadcastToLAN); + this.putBoolean(this.broadcastToXboxLive); this.putBoolean(this.commandsEnabled); this.putBoolean(this.isTexturePacksRequired); this.putUnsignedVarInt(this.ruleDatas.length); for (RuleData rule : this.ruleDatas) { this.putRuleData(rule); } + this.putBoolean(this.bonusChest); + this.putBoolean(this.trustPlayers); + this.putVarInt(this.permissionLevel); + this.putVarInt(this.gamePublish); this.putString(this.levelId); this.putString(this.worldName); this.putString(this.premiumWorldTemplateId); this.putBoolean(this.unknown); this.putLLong(this.currentTick); + this.putVarInt(this.enchantmentSeed); } } diff --git a/src/main/java/cn/nukkit/network/protocol/StopSoundPacket.java b/src/main/java/cn/nukkit/network/protocol/StopSoundPacket.java index 0c9d45acfa..32cf956b50 100644 --- a/src/main/java/cn/nukkit/network/protocol/StopSoundPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/StopSoundPacket.java @@ -19,6 +19,7 @@ public void decode() { @Override public void encode() { + this.reset(); this.putString(this.name); this.putBoolean(this.stopAll); } diff --git a/src/main/java/cn/nukkit/network/protocol/StructureBlockUpdatePacket.java b/src/main/java/cn/nukkit/network/protocol/StructureBlockUpdatePacket.java new file mode 100644 index 0000000000..1d22735de2 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/StructureBlockUpdatePacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class StructureBlockUpdatePacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.STRUCTURE_BLOCK_UPDATE_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/SubClientLoginPacket.java b/src/main/java/cn/nukkit/network/protocol/SubClientLoginPacket.java new file mode 100644 index 0000000000..386e4f67cc --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/SubClientLoginPacket.java @@ -0,0 +1,19 @@ +package cn.nukkit.network.protocol; + +public class SubClientLoginPacket extends DataPacket { + + @Override + public byte pid() { + return ProtocolInfo.SUB_CLIENT_LOGIN_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + //TODO + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/TakeItemEntityPacket.java b/src/main/java/cn/nukkit/network/protocol/TakeItemEntityPacket.java index 93187f28c4..0604347484 100644 --- a/src/main/java/cn/nukkit/network/protocol/TakeItemEntityPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/TakeItemEntityPacket.java @@ -12,13 +12,15 @@ public class TakeItemEntityPacket extends DataPacket { @Override public void decode() { + this.target = this.getEntityRuntimeId(); + this.entityId = this.getEntityRuntimeId(); } @Override public void encode() { this.reset(); - this.putVarLong(this.target); - this.putVarLong(this.entityId); + this.putEntityRuntimeId(this.target); + this.putEntityRuntimeId(this.entityId); } @Override diff --git a/src/main/java/cn/nukkit/network/protocol/TelemetryEventPacket.java b/src/main/java/cn/nukkit/network/protocol/TelemetryEventPacket.java new file mode 100644 index 0000000000..d429d6ab8c --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/TelemetryEventPacket.java @@ -0,0 +1,26 @@ +package cn.nukkit.network.protocol; + +public class TelemetryEventPacket extends DataPacket { + + public long eid; + public int unknown1; + public byte unknown2; + + @Override + public byte pid() { + return ProtocolInfo.TELEMETRY_EVENT_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + this.reset(); + this.putVarLong(this.eid); + this.putVarInt(this.unknown1); + this.putByte(this.unknown2); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/TextPacket.java b/src/main/java/cn/nukkit/network/protocol/TextPacket.java index c975d1dcb7..29ef8c6dcf 100644 --- a/src/main/java/cn/nukkit/network/protocol/TextPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/TextPacket.java @@ -25,10 +25,12 @@ public byte pid() { public String source = ""; public String message = ""; public String[] parameters = new String[0]; + public boolean isLocalized = false; @Override public void decode() { this.type = (byte) getByte(); + this.isLocalized = this.getBoolean(); switch (type) { case TYPE_POPUP: case TYPE_CHAT: @@ -55,6 +57,7 @@ public void decode() { public void encode() { this.reset(); this.putByte(this.type); + this.putBoolean(this.isLocalized); switch (this.type) { case TYPE_POPUP: case TYPE_CHAT: diff --git a/src/main/java/cn/nukkit/network/protocol/TransferPacket.java b/src/main/java/cn/nukkit/network/protocol/TransferPacket.java index 2ba3af1e8a..0c15ef2dd8 100644 --- a/src/main/java/cn/nukkit/network/protocol/TransferPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/TransferPacket.java @@ -3,10 +3,10 @@ // A wild TransferPacket appeared! public class TransferPacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.TRANSFER_PACKET; - + public String address; // Server address public int port = 19132; // Server port - + @Override public void decode() { this.address = this.getString(); diff --git a/src/main/java/cn/nukkit/network/protocol/UpdateAttributesPacket.java b/src/main/java/cn/nukkit/network/protocol/UpdateAttributesPacket.java index eef6281ac6..d720f86e5f 100644 --- a/src/main/java/cn/nukkit/network/protocol/UpdateAttributesPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/UpdateAttributesPacket.java @@ -24,7 +24,7 @@ public void decode() { public void encode() { this.reset(); - this.putVarLong(this.entityId); + this.putEntityRuntimeId(this.entityId); if (this.entries == null) { this.putUnsignedVarInt(0); diff --git a/src/main/java/cn/nukkit/network/protocol/UpdateBlockPacket.java b/src/main/java/cn/nukkit/network/protocol/UpdateBlockPacket.java index 1ca274b022..debadf376e 100644 --- a/src/main/java/cn/nukkit/network/protocol/UpdateBlockPacket.java +++ b/src/main/java/cn/nukkit/network/protocol/UpdateBlockPacket.java @@ -1,5 +1,6 @@ package cn.nukkit.network.protocol; + /** * author: MagicDroidX * Nukkit Project @@ -36,7 +37,7 @@ public void decode() { @Override public void encode() { this.reset(); - this.putBlockCoords(x, y, z); + this.putBlockVector3(x, y, z); this.putUnsignedVarInt(blockId); this.putUnsignedVarInt((0xb << 4) | blockData & 0xf); } diff --git a/src/main/java/cn/nukkit/network/protocol/UpdateEquipmentPacket.java b/src/main/java/cn/nukkit/network/protocol/UpdateEquipmentPacket.java new file mode 100644 index 0000000000..5a6f37ae42 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/UpdateEquipmentPacket.java @@ -0,0 +1,30 @@ +package cn.nukkit.network.protocol; + +public class UpdateEquipmentPacket extends DataPacket { + + public int windowId; + public int windowType; + public int unknown; //TODO: find out what this is (vanilla always sends 0) + public long eid; + public byte[] namedtag; + + + @Override + public byte pid() { + return ProtocolInfo.UPDATE_EQUIPMENT_PACKET; + } + + @Override + public void decode() { + + } + + @Override + public void encode() { + this.reset(); + this.putByte((byte) this.windowId); + this.putByte((byte) this.windowType); + this.putEntityUniqueId(this.eid); + this.put(this.namedtag); + } +} diff --git a/src/main/java/cn/nukkit/network/protocol/UpdateTradePacket.java b/src/main/java/cn/nukkit/network/protocol/UpdateTradePacket.java index 129ed4605e..28502ba3db 100644 --- a/src/main/java/cn/nukkit/network/protocol/UpdateTradePacket.java +++ b/src/main/java/cn/nukkit/network/protocol/UpdateTradePacket.java @@ -4,8 +4,8 @@ public class UpdateTradePacket extends DataPacket { public static final byte NETWORK_ID = ProtocolInfo.UPDATE_TRADE_PACKET; - public byte unknownByte1; - public byte unknownByte2; + public byte windowId; + public byte windowType = 15; //trading id public int unknownVarInt1; public int unknownVarInt2; public boolean isWilling; @@ -26,13 +26,14 @@ public void decode() { @Override public void encode() { - this.putByte(unknownByte1); - this.putByte(unknownByte2); + this.reset(); + this.putByte(windowId); + this.putByte(windowType); this.putVarInt(unknownVarInt1); this.putVarInt(unknownVarInt2); this.putBoolean(isWilling); - this.putVarLong(player); - this.putVarLong(trader); + this.putEntityUniqueId(player); + this.putEntityUniqueId(trader); this.putString(displayName); this.put(this.offers); } diff --git a/src/main/java/cn/nukkit/network/protocol/UseItemPacket.java b/src/main/java/cn/nukkit/network/protocol/UseItemPacket.java deleted file mode 100644 index a490656a18..0000000000 --- a/src/main/java/cn/nukkit/network/protocol/UseItemPacket.java +++ /dev/null @@ -1,64 +0,0 @@ -package cn.nukkit.network.protocol; - -import cn.nukkit.item.Item; -import cn.nukkit.math.BlockVector3; -import cn.nukkit.math.Vector3f; - -/** - * @author Nukkit Project Team - */ -public class UseItemPacket extends DataPacket { - - public static final byte NETWORK_ID = ProtocolInfo.USE_ITEM_PACKET; - - public int x; - public int y; - public int z; - - public int interactBlockId; - - public int face; - - public float fx; - public float fy; - public float fz; - - public float posX; - public float posY; - public float posZ; - - public int slot; - - public Item item; - - @Override - public byte pid() { - return NETWORK_ID; - } - - @Override - public void decode() { - BlockVector3 v = this.getBlockCoords(); - this.x = v.x; - this.y = v.y; - this.z = v.z; - this.interactBlockId = (int) this.getUnsignedVarInt(); - this.face = this.getVarInt(); - Vector3f faceVector3 = this.getVector3f(); - this.fx = faceVector3.x; - this.fy = faceVector3.y; - this.fz = faceVector3.z; - Vector3f playerPos = this.getVector3f(); - this.posX = playerPos.x; - this.posY = playerPos.y; - this.posZ = playerPos.z; - this.slot = this.getByte(); - this.item = this.getSlot(); - } - - @Override - public void encode() { - - } - -} diff --git a/src/main/java/cn/nukkit/network/protocol/types/ContainerIds.java b/src/main/java/cn/nukkit/network/protocol/types/ContainerIds.java new file mode 100644 index 0000000000..539b8098ca --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/types/ContainerIds.java @@ -0,0 +1,18 @@ +package cn.nukkit.network.protocol.types; + +/** + * @author CreeperFace + */ +public interface ContainerIds { + + int NONE = -1; + int INVENTORY = 0; + int FIRST = 1; + int LAST = 100; + int OFFHAND = 119; + int ARMOR = 120; + int CREATIVE = 121; + int HOTBAR = 122; + int FIXED_INVENTORY = 123; + int CURSOR = 124; +} diff --git a/src/main/java/cn/nukkit/network/protocol/types/NetworkInventoryAction.java b/src/main/java/cn/nukkit/network/protocol/types/NetworkInventoryAction.java new file mode 100644 index 0000000000..ea76a85ec4 --- /dev/null +++ b/src/main/java/cn/nukkit/network/protocol/types/NetworkInventoryAction.java @@ -0,0 +1,233 @@ +package cn.nukkit.network.protocol.types; + +import cn.nukkit.Player; +import cn.nukkit.inventory.AnvilInventory; +import cn.nukkit.inventory.EnchantInventory; +import cn.nukkit.inventory.Inventory; +import cn.nukkit.inventory.transaction.action.CreativeInventoryAction; +import cn.nukkit.inventory.transaction.action.DropItemAction; +import cn.nukkit.inventory.transaction.action.InventoryAction; +import cn.nukkit.inventory.transaction.action.SlotChangeAction; +import cn.nukkit.item.Item; +import cn.nukkit.network.protocol.InventoryTransactionPacket; + +/** + * @author CreeperFace + */ +public class NetworkInventoryAction { + + public static final int SOURCE_CONTAINER = 0; + + public static final int SOURCE_WORLD = 2; //drop/pickup item entity + public static final int SOURCE_CREATIVE = 3; + public static final int SOURCE_TODO = 99999; + + /** + * Fake window IDs for the SOURCE_TODO type (99999) + *

+ * These identifiers are used for inventory source types which are not currently implemented server-side in MCPE. + * As a general rule of thumb, anything that doesn't have a permanent inventory is client-side. These types are + * to allow servers to track what is going on in client-side windows. + *

+ * Expect these to change in the future. + */ + public static final int SOURCE_TYPE_CRAFTING_ADD_INGREDIENT = -2; + public static final int SOURCE_TYPE_CRAFTING_REMOVE_INGREDIENT = -3; + public static final int SOURCE_TYPE_CRAFTING_RESULT = -4; + public static final int SOURCE_TYPE_CRAFTING_USE_INGREDIENT = -5; + + public static final int SOURCE_TYPE_ANVIL_INPUT = -10; + public static final int SOURCE_TYPE_ANVIL_MATERIAL = -11; + public static final int SOURCE_TYPE_ANVIL_RESULT = -12; + public static final int SOURCE_TYPE_ANVIL_OUTPUT = -13; + + public static final int SOURCE_TYPE_ENCHANT_INPUT = -15; + public static final int SOURCE_TYPE_ENCHANT_MATERIAL = -16; + public static final int SOURCE_TYPE_ENCHANT_OUTPUT = -17; + + public static final int SOURCE_TYPE_TRADING_INPUT_1 = -20; + public static final int SOURCE_TYPE_TRADING_INPUT_2 = -21; + public static final int SOURCE_TYPE_TRADING_USE_INPUTS = -22; + public static final int SOURCE_TYPE_TRADING_OUTPUT = -23; + + public static final int SOURCE_TYPE_BEACON = -24; + + /** + * Any client-side window dropping its contents when the player closes it + */ + public static final int SOURCE_TYPE_CONTAINER_DROP_CONTENTS = -100; + + + public int sourceType; + public int windowId; + public long unknown; + public int inventorySlot; + public Item oldItem; + public Item newItem; + + public NetworkInventoryAction read(InventoryTransactionPacket packet) { + this.sourceType = (int) packet.getUnsignedVarInt(); + + switch (this.sourceType) { + case SOURCE_CONTAINER: + this.windowId = packet.getVarInt(); + break; + case SOURCE_WORLD: + this.unknown = packet.getUnsignedVarInt(); + break; + case SOURCE_CREATIVE: + break; + case SOURCE_TODO: + this.windowId = packet.getVarInt(); + break; + } + + this.inventorySlot = (int) packet.getUnsignedVarInt(); + this.oldItem = packet.getSlot(); + this.newItem = packet.getSlot(); + + return this; + } + + public void write(InventoryTransactionPacket packet) { + packet.putUnsignedVarInt(this.sourceType); + + switch (this.sourceType) { + case SOURCE_CONTAINER: + packet.putVarInt(this.windowId); + break; + case SOURCE_WORLD: + packet.putUnsignedVarInt(this.unknown); + break; + case SOURCE_CREATIVE: + break; + case SOURCE_TODO: + packet.putVarInt(this.windowId); + break; + } + + packet.putUnsignedVarInt(this.inventorySlot); + packet.putSlot(this.oldItem); + packet.putSlot(this.newItem); + } + + public InventoryAction createInventoryAction(Player player) { + switch (this.sourceType) { + case SOURCE_CONTAINER: + if (this.windowId == ContainerIds.ARMOR) { + //TODO: HACK! + this.inventorySlot += 36; + this.windowId = ContainerIds.INVENTORY; + } + + Inventory window = player.getWindowById(this.windowId); + if (window != null) { + return new SlotChangeAction(window, this.inventorySlot, this.oldItem, this.newItem); + } + + throw new RuntimeException("Player " + player.getName() + " has no open container with window ID " + this.windowId); + case SOURCE_WORLD: + if (this.inventorySlot != InventoryTransactionPacket.ACTION_MAGIC_SLOT_DROP_ITEM) { + throw new RuntimeException("Only expecting drop-item world actions from the client!"); + } + + return new DropItemAction(this.oldItem, this.newItem); + case SOURCE_CREATIVE: + int type; + + switch (this.inventorySlot) { + case InventoryTransactionPacket.ACTION_MAGIC_SLOT_CREATIVE_DELETE_ITEM: + type = CreativeInventoryAction.TYPE_DELETE_ITEM; + break; + case InventoryTransactionPacket.ACTION_MAGIC_SLOT_CREATIVE_CREATE_ITEM: + type = CreativeInventoryAction.TYPE_CREATE_ITEM; + break; + default: + throw new RuntimeException("Unexpected creative action type " + this.inventorySlot); + + } + + return new CreativeInventoryAction(this.oldItem, this.newItem, type); + case SOURCE_TODO: + //These types need special handling. + switch (this.windowId) { + case SOURCE_TYPE_CRAFTING_ADD_INGREDIENT: + case SOURCE_TYPE_CRAFTING_REMOVE_INGREDIENT: + case SOURCE_TYPE_CRAFTING_RESULT: + case SOURCE_TYPE_CRAFTING_USE_INGREDIENT: + window = player.getCraftingGrid(); + return new SlotChangeAction(window, this.inventorySlot, this.oldItem, this.newItem); + case SOURCE_TYPE_CONTAINER_DROP_CONTENTS: + window = player.getCraftingGrid(); + inventorySlot = window.first(this.oldItem, true); + if (inventorySlot == -1) { + throw new RuntimeException("Fake container " + window.getClass().getName() + " for " + player.getName() + " does not contain " + this.oldItem); + } + return new SlotChangeAction(window, inventorySlot, this.oldItem, this.newItem); + } + + if (this.windowId >= SOURCE_TYPE_ANVIL_OUTPUT && this.windowId <= SOURCE_TYPE_ANVIL_INPUT) { //anvil actions + Inventory inv = player.getWindowById(Player.ANVIL_WINDOW_ID); + + if (!(inv instanceof AnvilInventory)) { + throw new RuntimeException("Player " + player.getName() + " has no open anvil inventory"); + } + AnvilInventory anvil = (AnvilInventory) inv; + + switch (this.windowId) { + case SOURCE_TYPE_ANVIL_INPUT: + //System.out.println("action input"); + this.inventorySlot = 0; + return new SlotChangeAction(anvil, this.inventorySlot, this.oldItem, this.newItem); + case SOURCE_TYPE_ANVIL_MATERIAL: + //System.out.println("material"); + this.inventorySlot = 1; + return new SlotChangeAction(anvil, this.inventorySlot, this.oldItem, this.newItem); + case SOURCE_TYPE_ANVIL_OUTPUT: + //System.out.println("action output"); + break; + case SOURCE_TYPE_ANVIL_RESULT: + this.inventorySlot = 2; + anvil.clear(0); + anvil.clear(1); + anvil.setItem(2, this.oldItem); + //System.out.println("action result"); + return new SlotChangeAction(anvil, this.inventorySlot, this.oldItem, this.newItem); + } + } + + if (this.windowId >= SOURCE_TYPE_ENCHANT_OUTPUT && this.windowId <= SOURCE_TYPE_ENCHANT_INPUT) { + Inventory inv = player.getWindowById(Player.ENCHANT_WINDOW_ID); + + if (!(inv instanceof EnchantInventory)) { + throw new RuntimeException("Player " + player.getName() + " has no open enchant inventory"); + } + EnchantInventory enchant = (EnchantInventory) inv; + + switch (this.windowId) { + case SOURCE_TYPE_ENCHANT_INPUT: + this.inventorySlot = 0; + Item local = enchant.getItem(0); + if (local.equals(this.newItem, true, false)) { + enchant.setItem(0, this.newItem); + } + break; + case SOURCE_TYPE_ENCHANT_MATERIAL: + this.inventorySlot = 1; + break; + case SOURCE_TYPE_ENCHANT_OUTPUT: + enchant.sendSlot(0, player); + //ignore? + return null; + } + + return new SlotChangeAction(enchant, this.inventorySlot, this.oldItem, this.newItem); + } + + //TODO: more stuff + throw new RuntimeException("Player " + player.getName() + " has no open container with window ID " + this.windowId); + default: + throw new RuntimeException("Unknown inventory source type " + this.sourceType); + } + } +} diff --git a/src/main/java/cn/nukkit/network/query/QueryHandler.java b/src/main/java/cn/nukkit/network/query/QueryHandler.java index de232afe81..ff5fee844f 100644 --- a/src/main/java/cn/nukkit/network/query/QueryHandler.java +++ b/src/main/java/cn/nukkit/network/query/QueryHandler.java @@ -28,7 +28,7 @@ public QueryHandler() { this.server = Server.getInstance(); this.server.getLogger().info(this.server.getLanguage().translateString("nukkit.server.query.start")); String ip = this.server.getIp(); - String addr = (!"".equals(ip)) ? ip : "0.0.0.0"; + String addr = (!ip.isEmpty()) ? ip : "0.0.0.0"; int port = this.server.getPort(); this.server.getLogger().info(this.server.getLanguage().translateString("nukkit.server.query.info", String.valueOf(port))); diff --git a/src/main/java/cn/nukkit/potion/Effect.java b/src/main/java/cn/nukkit/potion/Effect.java index a2fbf92b16..b6d47800a3 100644 --- a/src/main/java/cn/nukkit/potion/Effect.java +++ b/src/main/java/cn/nukkit/potion/Effect.java @@ -261,6 +261,11 @@ public void add(Entity entity, boolean modify) { entity.setDataFlag(Entity.DATA_FLAGS, Entity.DATA_FLAG_INVISIBLE, true); entity.setNameTagVisible(false); } + + if (this.id == Effect.ABSORPTION) { + int add = (this.amplifier + 1) * 4; + if (add > entity.getAbsorption()) entity.setAbsorption(add); + } } public void remove(Entity entity) { @@ -281,6 +286,10 @@ public void remove(Entity entity) { entity.setDataFlag(Entity.DATA_FLAGS, Entity.DATA_FLAG_INVISIBLE, false); entity.setNameTagVisible(true); } + + if (this.id == Effect.ABSORPTION) { + entity.setAbsorption(0); + } } @Override diff --git a/src/main/java/cn/nukkit/raknet/server/SessionManager.java b/src/main/java/cn/nukkit/raknet/server/SessionManager.java index d5252f15eb..df6053554e 100644 --- a/src/main/java/cn/nukkit/raknet/server/SessionManager.java +++ b/src/main/java/cn/nukkit/raknet/server/SessionManager.java @@ -82,7 +82,7 @@ private void tickProcessor() throws Exception { } --max; } catch (Exception e) { - if (!"".equals(currentSource)) { + if (!currentSource.isEmpty()) { this.blockAddress(currentSource); } // else ignore diff --git a/src/main/java/cn/nukkit/resourcepacks/AbstractResourcePack.java b/src/main/java/cn/nukkit/resourcepacks/AbstractResourcePack.java index 440435e0d9..0c6ae3fdb3 100644 --- a/src/main/java/cn/nukkit/resourcepacks/AbstractResourcePack.java +++ b/src/main/java/cn/nukkit/resourcepacks/AbstractResourcePack.java @@ -9,7 +9,7 @@ public abstract class AbstractResourcePack implements ResourcePack { protected boolean verifyManifest() { if (this.manifest.has("format_version") && this.manifest.has("header") && this.manifest.has("modules")) { JsonObject header = this.manifest.getAsJsonObject("header"); - return header.has("description") && + return header.has("description") && header.has("name") && header.has("uuid") && header.has("version") && diff --git a/src/main/java/cn/nukkit/scheduler/NukkitRunnable.java b/src/main/java/cn/nukkit/scheduler/NukkitRunnable.java index ee992d88f5..55db31ab63 100644 --- a/src/main/java/cn/nukkit/scheduler/NukkitRunnable.java +++ b/src/main/java/cn/nukkit/scheduler/NukkitRunnable.java @@ -24,31 +24,31 @@ public synchronized Runnable runTask(Plugin plugin) throws IllegalArgumentExcept return taskHandler.getTask(); } - public synchronized Runnable runTaskAsynchronously(Plugin plugin) throws IllegalArgumentException, IllegalStateException { + public synchronized Runnable runTaskAsynchronously(Plugin plugin) throws IllegalArgumentException, IllegalStateException { checkState(); this.taskHandler = Server.getInstance().getScheduler().scheduleTask(plugin, this, true); return taskHandler.getTask(); } - public synchronized Runnable runTaskLater(Plugin plugin, int delay) throws IllegalArgumentException, IllegalStateException { + public synchronized Runnable runTaskLater(Plugin plugin, int delay) throws IllegalArgumentException, IllegalStateException { checkState(); this.taskHandler = Server.getInstance().getScheduler().scheduleDelayedTask(plugin, this, delay); return taskHandler.getTask(); } - public synchronized Runnable runTaskLaterAsynchronously(Plugin plugin, int delay) throws IllegalArgumentException, IllegalStateException { + public synchronized Runnable runTaskLaterAsynchronously(Plugin plugin, int delay) throws IllegalArgumentException, IllegalStateException { checkState(); this.taskHandler = Server.getInstance().getScheduler().scheduleDelayedTask(plugin, this, delay, true); return taskHandler.getTask(); } - public synchronized Runnable runTaskTimer(Plugin plugin, int delay, int period) throws IllegalArgumentException, IllegalStateException { + public synchronized Runnable runTaskTimer(Plugin plugin, int delay, int period) throws IllegalArgumentException, IllegalStateException { checkState(); this.taskHandler = Server.getInstance().getScheduler().scheduleDelayedRepeatingTask(plugin, this, delay, period); return taskHandler.getTask(); } - public synchronized Runnable runTaskTimerAsynchronously(Plugin plugin, int delay, int period) throws IllegalArgumentException, IllegalStateException { + public synchronized Runnable runTaskTimerAsynchronously(Plugin plugin, int delay, int period) throws IllegalArgumentException, IllegalStateException { checkState(); this.taskHandler = Server.getInstance().getScheduler().scheduleDelayedRepeatingTask(plugin, this, delay, period, true); return taskHandler.getTask(); diff --git a/src/main/java/cn/nukkit/scheduler/ServerScheduler.java b/src/main/java/cn/nukkit/scheduler/ServerScheduler.java index c07e6ef469..ad62bafbd0 100644 --- a/src/main/java/cn/nukkit/scheduler/ServerScheduler.java +++ b/src/main/java/cn/nukkit/scheduler/ServerScheduler.java @@ -57,7 +57,7 @@ public TaskHandler scheduleTask(Runnable task) { public TaskHandler scheduleTask(Plugin plugin, Runnable task) { return addTask(plugin, task, 0, 0, false); } - + /** * @deprecated Use {@link #scheduleTask(Plugin, Runnable, boolean) */ @@ -69,7 +69,7 @@ public TaskHandler scheduleTask(Runnable task, boolean asynchronous) { public TaskHandler scheduleTask(Plugin plugin, Runnable task, boolean asynchronous) { return addTask(plugin, task, 0, 0, asynchronous); } - + /** * @deprecated Use {@link #scheduleAsyncTask(Plugin, AsyncTask) */ @@ -81,7 +81,7 @@ public TaskHandler scheduleAsyncTask(AsyncTask task) { public TaskHandler scheduleAsyncTask(Plugin plugin, AsyncTask task) { return addTask(plugin, task, 0, 0, true); } - + @Deprecated public void scheduleAsyncTaskToWorker(AsyncTask task, int worker) { scheduleAsyncTask(task); @@ -114,7 +114,7 @@ public TaskHandler scheduleDelayedTask(Runnable task, int delay) { public TaskHandler scheduleDelayedTask(Plugin plugin, Runnable task, int delay) { return addTask(plugin, task, delay, 0, false); } - + /** * @deprecated Use {@link #scheduleDelayedTask(Plugin, Runnable, int, boolean) */ @@ -126,7 +126,7 @@ public TaskHandler scheduleDelayedTask(Runnable task, int delay, boolean asynchr public TaskHandler scheduleDelayedTask(Plugin plugin, Runnable task, int delay, boolean asynchronous) { return addTask(plugin, task, delay, 0, asynchronous); } - + /** * @deprecated Use {@link #scheduleRepeatingTask(Plugin, Runnable, int) */ @@ -134,7 +134,7 @@ public TaskHandler scheduleDelayedTask(Plugin plugin, Runnable task, int delay, public TaskHandler scheduleRepeatingTask(Runnable task, int period) { return addTask(null, task, 0, period, false); } - + public TaskHandler scheduleRepeatingTask(Plugin plugin, Runnable task, int period) { return addTask(plugin, task, 0, period, false); } @@ -150,7 +150,7 @@ public TaskHandler scheduleRepeatingTask(Runnable task, int period, boolean asyn public TaskHandler scheduleRepeatingTask(Plugin plugin, Runnable task, int period, boolean asynchronous) { return addTask(plugin, task, 0, period, asynchronous); } - + public TaskHandler scheduleRepeatingTask(Task task, int period) { return addTask(task, 0, period, false); } @@ -174,7 +174,7 @@ public TaskHandler scheduleDelayedRepeatingTask(Task task, int delay, int period public TaskHandler scheduleDelayedRepeatingTask(Runnable task, int delay, int period) { return addTask(null, task, delay, period, false); } - + public TaskHandler scheduleDelayedRepeatingTask(Plugin plugin, Runnable task, int delay, int period) { return addTask(plugin, task, delay, period, false); } @@ -186,7 +186,7 @@ public TaskHandler scheduleDelayedRepeatingTask(Plugin plugin, Runnable task, in public TaskHandler scheduleDelayedRepeatingTask(Runnable task, int delay, int period, boolean asynchronous) { return addTask(null, task, delay, period, asynchronous); } - + public TaskHandler scheduleDelayedRepeatingTask(Plugin plugin, Runnable task, int delay, int period, boolean asynchronous) { return addTask(plugin, task, delay, period, asynchronous); } diff --git a/src/main/java/cn/nukkit/utils/Binary.java b/src/main/java/cn/nukkit/utils/Binary.java index 9405f1b4e9..c07c44cf19 100644 --- a/src/main/java/cn/nukkit/utils/Binary.java +++ b/src/main/java/cn/nukkit/utils/Binary.java @@ -18,6 +18,30 @@ */ public class Binary { + public static int signByte(int value) { + return value << 56 >> 56; + } + + public static int unsignByte(int value) { + return value & 0xff; + } + + public static int signShort(int value) { + return value << 48 >> 48; + } + + public int unsignShort(int value) { + return value & 0xffff; + } + + public static int signInt(int value) { + return value << 32 >> 32; + } + + public static int unsignInt(int value) { + return value; + } + //Triad: {0x00,0x00,0x01}<=>1 public static int readTriad(byte[] bytes) { return readInt(new byte[]{ @@ -55,7 +79,7 @@ public static byte[] writeLTriad(int value) { } public static UUID readUUID(byte[] bytes) { - return new UUID(readLong(bytes), readLong(new byte[]{ + return new UUID(readLLong(bytes), readLLong(new byte[]{ bytes[8], bytes[9], bytes[10], @@ -68,7 +92,7 @@ public static UUID readUUID(byte[] bytes) { } public static byte[] writeUUID(UUID uuid) { - return appendBytes(writeLong(uuid.getMostSignificantBits()), writeLong(uuid.getLeastSignificantBits())); + return appendBytes(writeLLong(uuid.getMostSignificantBits()), writeLLong(uuid.getLeastSignificantBits())); } public static byte[] writeMetadata(EntityMetadata metadata) { @@ -99,14 +123,12 @@ public static byte[] writeMetadata(EntityMetadata metadata) { break; case Entity.DATA_TYPE_SLOT: SlotEntityData slot = (SlotEntityData) d; - stream.putLShort(slot.blockId); - stream.putByte((byte) slot.meta); - stream.putLShort(slot.count); + stream.putSlot(slot.getData()); break; case Entity.DATA_TYPE_POS: IntPositionEntityData pos = (IntPositionEntityData) d; stream.putVarInt(pos.x); - stream.putByte((byte) pos.y); + stream.putVarInt(pos.y); stream.putVarInt(pos.z); break; case Entity.DATA_TYPE_LONG: @@ -153,7 +175,7 @@ public static EntityMetadata readMetadata(byte[] payload) { value = new SlotEntityData(key, item.getId(), item.getDamage(), item.getCount()); break; case Entity.DATA_TYPE_POS: - BlockVector3 v3 = stream.getBlockCoords(); + BlockVector3 v3 = stream.getSignedBlockPosition(); value = new IntPositionEntityData(key, v3.x, v3.y, v3.z); break; case Entity.DATA_TYPE_LONG: diff --git a/src/main/java/cn/nukkit/utils/BinaryStream.java b/src/main/java/cn/nukkit/utils/BinaryStream.java index 65dbb8637f..170bfee573 100644 --- a/src/main/java/cn/nukkit/utils/BinaryStream.java +++ b/src/main/java/cn/nukkit/utils/BinaryStream.java @@ -3,10 +3,10 @@ import cn.nukkit.entity.Attribute; import cn.nukkit.entity.data.Skin; import cn.nukkit.item.Item; +import cn.nukkit.math.BlockFace; import cn.nukkit.math.BlockVector3; import cn.nukkit.math.Vector3f; -import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -204,27 +204,22 @@ public void putByte(byte b) { /** * Reads a list of Attributes from the stream. + * * @return Attribute[] */ public Attribute[] getAttributeList() throws Exception { List list = new ArrayList<>(); long count = this.getUnsignedVarInt(); - for(int i = 0; i < count; ++i){ - float min = this.getLFloat(); - float max = this.getLFloat(); - float current = this.getLFloat(); - float defaultValue = this.getLFloat(); + for (int i = 0; i < count; ++i) { String name = this.getString(); - Attribute attr = Attribute.getAttributeByName(name); - if(attr != null){ - attr.setMinValue(min); - attr.setMaxValue(max); - attr.setValue(current); - attr.setDefaultValue(defaultValue); + if (attr != null) { + attr.setMinValue(this.getLFloat()); + attr.setValue(this.getLFloat()); + attr.setMaxValue(this.getLFloat()); list.add(attr); - }else{ + } else { throw new Exception("Unknown attribute type \"" + name + "\""); } } @@ -235,14 +230,13 @@ public Attribute[] getAttributeList() throws Exception { /** * Writes a list of Attributes to the packet buffer using the standard format. */ - public void putAttributeList(Attribute[] attributes){ + public void putAttributeList(Attribute[] attributes) { this.putUnsignedVarInt(attributes.length); - for (Attribute attribute: attributes){ + for (Attribute attribute : attributes) { + this.putString(attribute.getName()); this.putLFloat(attribute.getMinValue()); - this.putLFloat(attribute.getMaxValue()); this.putLFloat(attribute.getValue()); - this.putLFloat(attribute.getDefaultValue()); - this.putString(attribute.getName()); + this.putLFloat(attribute.getMaxValue()); } } @@ -286,16 +280,16 @@ public Item getSlot() { //TODO int canPlaceOn = this.getVarInt(); - if(canPlaceOn > 0){ - for(int i = 0; i < canPlaceOn; ++i){ + if (canPlaceOn > 0) { + for (int i = 0; i < canPlaceOn; ++i) { this.getString(); } } //TODO int canDestroy = this.getVarInt(); - if(canDestroy > 0){ - for(int i = 0; i < canDestroy; ++i){ + if (canDestroy > 0) { + for (int i = 0; i < canDestroy; ++i) { this.getString(); } } @@ -371,11 +365,25 @@ public void putUnsignedVarLong(long v) { VarInt.writeUnsignedVarLong(this, v); } - public BlockVector3 getBlockCoords() { + public BlockVector3 getBlockVector3() { return new BlockVector3(this.getVarInt(), (int) this.getUnsignedVarInt(), this.getVarInt()); } - public void putBlockCoords(int x, int y, int z) { + public BlockVector3 getSignedBlockPosition() { + return new BlockVector3(getVarInt(), getVarInt(), getVarInt()); + } + + public void putSignedBlockPosition(BlockVector3 v) { + putVarInt(v.x); + putVarInt(v.y); + putVarInt(v.z); + } + + public void putBlockVector3(BlockVector3 v) { + this.putBlockVector3(v.x, v.y, v.z); + } + + public void putBlockVector3(int x, int y, int z) { this.putVarInt(x); this.putUnsignedVarInt(y); this.putVarInt(z); @@ -385,6 +393,10 @@ public Vector3f getVector3f() { return new Vector3f(this.getLFloat(4), this.getLFloat(4), this.getLFloat(4)); } + public void putVector3f(Vector3f v) { + this.putVector3f(v.x, v.y, v.z); + } + public void putVector3f(float x, float y, float z) { this.putLFloat(x); this.putLFloat(y); @@ -405,6 +417,44 @@ public void putRuleData(RuleData rule) { this.putBoolean(rule.unknown2); } + /** + * Reads and returns an EntityUniqueID + * + * @return int + */ + public long getEntityUniqueId() { + return this.getVarLong(); + } + + /** + * Writes an EntityUniqueID + */ + public void putEntityUniqueId(long eid) { + this.putVarLong(eid); + } + + /** + * Reads and returns an EntityRuntimeID + */ + public long getEntityRuntimeId() { + return this.getUnsignedVarLong(); + } + + /** + * Writes an EntityUniqueID + */ + public void putEntityRuntimeId(long eid) { + this.putUnsignedVarLong(eid); + } + + public BlockFace getBlockFace() { + return BlockFace.fromIndex(this.getVarInt()); + } + + public void putBlockFace(BlockFace face) { + this.putVarInt(face.getIndex()); + } + public boolean feof() { return this.offset < 0 || this.offset >= this.buffer.length; } diff --git a/src/main/java/cn/nukkit/utils/ClientChainData.java b/src/main/java/cn/nukkit/utils/ClientChainData.java index b444d04100..358bd6fd25 100644 --- a/src/main/java/cn/nukkit/utils/ClientChainData.java +++ b/src/main/java/cn/nukkit/utils/ClientChainData.java @@ -10,182 +10,192 @@ /** * ClientChainData is a container of chain data sent from clients. - * + *

* Device information such as client UUID, xuid and serverAddress, can be * read from instances of this object. - * + *

* To get chain data, you can use player.getLoginChainData() or read(loginPacket) - * + *

* =============== * author: boybook * Nukkit Project * =============== */ -public final class ClientChainData { +public final class ClientChainData implements LoginChainData { - public static ClientChainData of(byte[] buffer) { - return new ClientChainData(buffer); - } - - public static ClientChainData read(LoginPacket pk) { - return of(pk.getBuffer()); - } - - public String getUsername() { - return username; - } - - public UUID getClientUUID() { - return clientUUID; - } - - public String getIdentityPublicKey() { - return identityPublicKey; - } - - public long getClientId() { - return clientId; - } - - public String getServerAddress() { - return serverAddress; - } - - public String getDeviceModel() { - return deviceModel; - } - - public int getDeviceOS() { - return deviceOS; - } - - public String getGameVersion() { - return gameVersion; - } - - public int getGuiScale() { - return guiScale; - } - - public String getLanguageCode() { - return languageCode; - } - - public String getXUID() { - return xuid; - } - - public int getCurrentInputMode() { - return currentInputMode; - } - - public int getDefaultInputMode() { - return defaultInputMode; - } - - public String getADRole() { - return ADRole; - } - - public String getTenantId() { - return tenantId; - } - - public final static int UI_PROFILE_CLASSIC = 0; - public final static int UI_PROFILE_POCKET = 1; - - public int getUIProfile() { - return UIProfile; - } - - /////////////////////////////////////////////////////////////////////////// - // Override - /////////////////////////////////////////////////////////////////////////// - - @Override - public boolean equals(Object obj) { - return obj instanceof ClientChainData && Objects.equals(bs, ((ClientChainData) obj).bs); - } - - @Override - public int hashCode() { - return bs.hashCode(); - } - - /////////////////////////////////////////////////////////////////////////// - // Internal - /////////////////////////////////////////////////////////////////////////// - - private String username; - private UUID clientUUID; - private String xuid; - private String identityPublicKey; - - private long clientId; - private String serverAddress; - private String deviceModel; - private int deviceOS; - private String gameVersion; - private int guiScale; - private String languageCode; - private int currentInputMode; - private int defaultInputMode; - private String ADRole; - private String tenantId; - - private int UIProfile; - - private BinaryStream bs = new BinaryStream(); - - private ClientChainData(byte[] buffer) { - bs.setBuffer(buffer, 0); - decodeChainData(); - decodeSkinData(); - } - - private void decodeChainData() { - Map> map = new Gson().fromJson(new String(bs.get(bs.getLInt()), StandardCharsets.UTF_8), - new TypeToken>>() { - }.getType()); - if (map.isEmpty() || !map.containsKey("chain") || map.get("chain").isEmpty()) return; - List chains = map.get("chain"); - for (String c : chains) { - JsonObject chainMap = decodeToken(c); - if (chainMap == null) continue; - if (chainMap.has("extraData")) { - JsonObject extra = chainMap.get("extraData").getAsJsonObject(); - if (extra.has("displayName")) this.username = extra.get("displayName").getAsString(); - if (extra.has("identity")) this.clientUUID = UUID.fromString(extra.get("identity").getAsString()); - if (extra.has("XUID")) this.xuid = extra.get("XUID").getAsString(); - } - if (chainMap.has("identityPublicKey")) - this.identityPublicKey = chainMap.get("identityPublicKey").getAsString(); - } - } - - private void decodeSkinData() { - JsonObject skinToken = decodeToken(new String(bs.get(bs.getLInt()))); - if(skinToken == null) return; - if (skinToken.has("ClientRandomId")) this.clientId = skinToken.get("ClientRandomId").getAsLong(); - if (skinToken.has("ServerAddress")) this.serverAddress = skinToken.get("ServerAddress").getAsString(); - if (skinToken.has("DeviceModel")) this.deviceModel = skinToken.get("DeviceModel").getAsString(); - if (skinToken.has("DeviceOS")) this.deviceOS = skinToken.get("DeviceOS").getAsInt(); - if (skinToken.has("GameVersion")) this.gameVersion = skinToken.get("GameVersion").getAsString(); - if (skinToken.has("GuiScale")) this.guiScale = skinToken.get("GuiScale").getAsInt(); - if (skinToken.has("LanguageCode")) this.languageCode = skinToken.get("LanguageCode").getAsString(); - if (skinToken.has("CurrentInputMode")) this.currentInputMode = skinToken.get("CurrentInputMode").getAsInt(); - if (skinToken.has("DefaultInputMode")) this.defaultInputMode = skinToken.get("DefaultInputMode").getAsInt(); - if (skinToken.has("ADRole")) this.ADRole = skinToken.get("ADRole").getAsString(); - if (skinToken.has("TenantId")) this.tenantId = skinToken.get("TenantId").getAsString(); - if (skinToken.has("UIProfile")) this.UIProfile = skinToken.get("UIProfile").getAsInt(); - } - - private JsonObject decodeToken(String token) { - String[] base = token.split("\\."); - if (base.length < 2) return null; - String json = new String(Base64.getDecoder().decode(base[1]), StandardCharsets.UTF_8); - //Server.getInstance().getLogger().debug(json); - return new Gson().fromJson(json, JsonObject.class); - } + public static ClientChainData of(byte[] buffer) { + return new ClientChainData(buffer); + } + + public static ClientChainData read(LoginPacket pk) { + return of(pk.getBuffer()); + } + + @Override + public String getUsername() { + return username; + } + + @Override + public UUID getClientUUID() { + return clientUUID; + } + + @Override + public String getIdentityPublicKey() { + return identityPublicKey; + } + + @Override + public long getClientId() { + return clientId; + } + + @Override + public String getServerAddress() { + return serverAddress; + } + + @Override + public String getDeviceModel() { + return deviceModel; + } + + @Override + public int getDeviceOS() { + return deviceOS; + } + + @Override + public String getGameVersion() { + return gameVersion; + } + + @Override + public int getGuiScale() { + return guiScale; + } + + @Override + public String getLanguageCode() { + return languageCode; + } + + @Override + public String getXUID() { + return xuid; + } + + @Override + public int getCurrentInputMode() { + return currentInputMode; + } + + @Override + public int getDefaultInputMode() { + return defaultInputMode; + } + + @Override + public String getCapeData() { + return capeData; + } + + public final static int UI_PROFILE_CLASSIC = 0; + public final static int UI_PROFILE_POCKET = 1; + + @Override + public int getUIProfile() { + return UIProfile; + } + + /////////////////////////////////////////////////////////////////////////// + // Override + /////////////////////////////////////////////////////////////////////////// + + @Override + public boolean equals(Object obj) { + return obj instanceof ClientChainData && Objects.equals(bs, ((ClientChainData) obj).bs); + } + + @Override + public int hashCode() { + return bs.hashCode(); + } + + /////////////////////////////////////////////////////////////////////////// + // Internal + /////////////////////////////////////////////////////////////////////////// + + private String username; + private UUID clientUUID; + private String xuid; + private String identityPublicKey; + + private long clientId; + private String serverAddress; + private String deviceModel; + private int deviceOS; + private String gameVersion; + private int guiScale; + private String languageCode; + private int currentInputMode; + private int defaultInputMode; + + private int UIProfile; + + private String capeData; + + private BinaryStream bs = new BinaryStream(); + + private ClientChainData(byte[] buffer) { + bs.setBuffer(buffer, 0); + decodeChainData(); + decodeSkinData(); + } + + private void decodeChainData() { + Map> map = new Gson().fromJson(new String(bs.get(bs.getLInt()), StandardCharsets.UTF_8), + new TypeToken>>() { + }.getType()); + if (map.isEmpty() || !map.containsKey("chain") || map.get("chain").isEmpty()) return; + List chains = map.get("chain"); + for (String c : chains) { + JsonObject chainMap = decodeToken(c); + if (chainMap == null) continue; + if (chainMap.has("extraData")) { + JsonObject extra = chainMap.get("extraData").getAsJsonObject(); + if (extra.has("displayName")) this.username = extra.get("displayName").getAsString(); + if (extra.has("identity")) this.clientUUID = UUID.fromString(extra.get("identity").getAsString()); + if (extra.has("XUID")) this.xuid = extra.get("XUID").getAsString(); + } + if (chainMap.has("identityPublicKey")) + this.identityPublicKey = chainMap.get("identityPublicKey").getAsString(); + } + } + + private void decodeSkinData() { + JsonObject skinToken = decodeToken(new String(bs.get(bs.getLInt()))); + if (skinToken == null) return; + if (skinToken.has("ClientRandomId")) this.clientId = skinToken.get("ClientRandomId").getAsLong(); + if (skinToken.has("ServerAddress")) this.serverAddress = skinToken.get("ServerAddress").getAsString(); + if (skinToken.has("DeviceModel")) this.deviceModel = skinToken.get("DeviceModel").getAsString(); + if (skinToken.has("DeviceOS")) this.deviceOS = skinToken.get("DeviceOS").getAsInt(); + if (skinToken.has("GameVersion")) this.gameVersion = skinToken.get("GameVersion").getAsString(); + if (skinToken.has("GuiScale")) this.guiScale = skinToken.get("GuiScale").getAsInt(); + if (skinToken.has("LanguageCode")) this.languageCode = skinToken.get("LanguageCode").getAsString(); + if (skinToken.has("CurrentInputMode")) this.currentInputMode = skinToken.get("CurrentInputMode").getAsInt(); + if (skinToken.has("DefaultInputMode")) this.defaultInputMode = skinToken.get("DefaultInputMode").getAsInt(); + if (skinToken.has("UIProfile")) this.UIProfile = skinToken.get("UIProfile").getAsInt(); + if (skinToken.has("CapeData")) this.capeData = skinToken.get("CapeData").getAsString(); + } + + private JsonObject decodeToken(String token) { + String[] base = token.split("\\."); + if (base.length < 2) return null; + String json = new String(Base64.getDecoder().decode(base[1]), StandardCharsets.UTF_8); + //Server.getInstance().getLogger().debug(json); + return new Gson().fromJson(json, JsonObject.class); + } } diff --git a/src/main/java/cn/nukkit/utils/ConfigSection.java b/src/main/java/cn/nukkit/utils/ConfigSection.java index bdab8c57d3..05bb97b2fd 100644 --- a/src/main/java/cn/nukkit/utils/ConfigSection.java +++ b/src/main/java/cn/nukkit/utils/ConfigSection.java @@ -133,17 +133,17 @@ public ConfigSection getSection(String key) { /** * Get all ConfigSections in root path. * Example config: - * a1: - * b1: - * c1: - * c2: - * a2: - * b2: - * c3: - * c4: - * a3: true - * a4: "hello" - * a5: 100 + * a1: + * b1: + * c1: + * c2: + * a2: + * b2: + * c3: + * c4: + * a3: true + * a4: "hello" + * a5: 100 *

* getSections() will return new ConfigSection, that contains sections a1 and a2 only. * diff --git a/src/main/java/cn/nukkit/utils/DummyBossBar.java b/src/main/java/cn/nukkit/utils/DummyBossBar.java new file mode 100644 index 0000000000..0fb66b68ec --- /dev/null +++ b/src/main/java/cn/nukkit/utils/DummyBossBar.java @@ -0,0 +1,243 @@ +package cn.nukkit.utils; + +import cn.nukkit.Player; +import cn.nukkit.entity.Attribute; +import cn.nukkit.entity.Entity; +import cn.nukkit.entity.data.EntityMetadata; +import cn.nukkit.entity.mob.EntityCreeper; +import cn.nukkit.network.protocol.*; + +import java.awt.*; +import java.util.concurrent.ThreadLocalRandom; + +/** + * DummyBossBar + * =============== + * author: boybook + * Nukkit Project + * =============== + */ +public class DummyBossBar { + + private final Player player; + private final long bossBarId; + + private String text; + private float length; + private Color color; + + private DummyBossBar(Builder builder) { + this.player = builder.player; + this.bossBarId = builder.bossBarId; + this.text = builder.text; + this.length = builder.length; + this.color = builder.color; + } + + public static class Builder { + private final Player player; + private final long bossBarId; + + private String text = ""; + private float length = 100; + private Color color = null; + + public Builder(Player player) { + this.player = player; + this.bossBarId = 1095216660480L + ThreadLocalRandom.current().nextLong(0, 0x7fffffffL); + } + + public Builder text(String text) { + this.text = text; + return this; + } + + public Builder length(float length) { + if (length >= 0 && length <= 100) this.length = length; + return this; + } + + public Builder color(Color color) { + this.color = color; + return this; + } + + public Builder color(int red, int green, int blue) { + return color(new Color(red, green, blue)); + } + + public DummyBossBar build() { + return new DummyBossBar(this); + } + } + + public Player getPlayer() { + return player; + } + + public long getBossBarId() { + return bossBarId; + } + + public String getText() { + return text; + } + + public void setText(String text) { + if (!this.text.equals(text)) { + this.text = text; + this.updateBossEntityNameTag(); + this.sendSetBossBarTitle(); + } + } + + public float getLength() { + return length; + } + + public void setLength(float length) { + if (this.length != length) { + this.length = length; + this.sendAttributes(); + } + } + + /** + * Color is not working in the current version. We are keep waiting for client support. + * @param color the boss bar color + */ + public void setColor(Color color) { + if (this.color == null || !this.color.equals(color)) { + this.color = color; + this.sendSetBossBarTexture(); + } + } + + public void setColor(int red, int green, int blue) { + this.setColor(new Color(red, green, blue)); + } + + public int getMixedColor() { + return this.color.getRGB();//(this.color.getRed() << 16 | this.color.getGreen() << 8 | this.color.getBlue()) & 0xffffff; + } + + public Color getColor() { + return this.color; + } + + private void createBossEntity() { + AddEntityPacket pkAdd = new AddEntityPacket(); + pkAdd.type = EntityCreeper.NETWORK_ID; + pkAdd.entityUniqueId = bossBarId; + pkAdd.entityRuntimeId = bossBarId; + pkAdd.x = (float) player.x; + pkAdd.y = (float) -10; // Below the bedrock + pkAdd.z = (float) player.z; + pkAdd.speedX = 0; + pkAdd.speedY = 0; + pkAdd.speedZ = 0; + pkAdd.metadata = new EntityMetadata() + // Default Metadata tags + .putLong(Entity.DATA_FLAGS, 0) + .putShort(Entity.DATA_AIR, 400) + .putShort(Entity.DATA_MAX_AIR, 400) + .putLong(Entity.DATA_LEAD_HOLDER_EID, -1) + .putString(Entity.DATA_NAMETAG, text) // Set the entity name + .putFloat(Entity.DATA_SCALE, 0); // And make it invisible + + player.dataPacket(pkAdd); + } + + private void sendAttributes() { + UpdateAttributesPacket pkAttributes = new UpdateAttributesPacket(); + pkAttributes.entityId = bossBarId; + Attribute attr = Attribute.getAttribute(Attribute.MAX_HEALTH); + attr.setMaxValue(100); // Max value - We need to change the max value first, or else the "setValue" will return a IllegalArgumentException + attr.setValue(length); // Entity health + pkAttributes.entries = new Attribute[]{attr}; + player.dataPacket(pkAttributes); + } + + private void sendShowBossBar() { + BossEventPacket pkBoss = new BossEventPacket(); + pkBoss.bossEid = bossBarId; + pkBoss.type = BossEventPacket.TYPE_SHOW; + pkBoss.title = text; + pkBoss.healthPercent = this.length; + player.dataPacket(pkBoss); + } + + private void sendHideBossBar() { + BossEventPacket pkBoss = new BossEventPacket(); + pkBoss.bossEid = bossBarId; + pkBoss.type = BossEventPacket.TYPE_HIDE; + player.dataPacket(pkBoss); + } + + private void sendSetBossBarTexture() { + BossEventPacket pk = new BossEventPacket(); + pk.bossEid = this.bossBarId; + pk.type = BossEventPacket.TYPE_TEXTURE; + pk.color = this.getMixedColor(); + player.dataPacket(pk); + } + + private void sendSetBossBarTitle() { + BossEventPacket pkBoss = new BossEventPacket(); + pkBoss.bossEid = bossBarId; + pkBoss.type = BossEventPacket.TYPE_TITLE; + pkBoss.title = text; + pkBoss.healthPercent = this.length; + player.dataPacket(pkBoss); + } + + /** + * Don't let the entity go too far from the player, or the BossBar will disappear. + * Update boss entity's position when teleport and each 5s. + */ + public void updateBossEntityPosition() { + MoveEntityPacket pk = new MoveEntityPacket(); + pk.eid = this.bossBarId; + pk.x = this.player.x; + pk.y = -10; + pk.z = this.player.z; + pk.headYaw = 0; + pk.yaw = 0; + pk.pitch = 0; + player.dataPacket(pk); + } + + private void updateBossEntityNameTag() { + SetEntityDataPacket pk = new SetEntityDataPacket(); + pk.eid = this.bossBarId; + pk.metadata = new EntityMetadata().putString(Entity.DATA_NAMETAG, this.text); + player.dataPacket(pk); + } + + private void removeBossEntity() { + RemoveEntityPacket pkRemove = new RemoveEntityPacket(); + pkRemove.eid = bossBarId; + player.dataPacket(pkRemove); + } + + public void create() { + createBossEntity(); + sendAttributes(); + sendShowBossBar(); + if (color != null) this.sendSetBossBarTexture(); + } + + /** + * Once the player has teleported, resend Show BossBar + */ + public void reshow() { + updateBossEntityPosition(); + sendShowBossBar(); + } + + public void destroy() { + sendHideBossBar(); + removeBossEntity(); + } + +} diff --git a/src/main/java/cn/nukkit/utils/LoginChainData.java b/src/main/java/cn/nukkit/utils/LoginChainData.java new file mode 100644 index 0000000000..f29fa36db3 --- /dev/null +++ b/src/main/java/cn/nukkit/utils/LoginChainData.java @@ -0,0 +1,39 @@ +package cn.nukkit.utils; + +import java.util.UUID; + +/** + * @author CreeperFace + */ +public interface LoginChainData { + + String getUsername(); + + UUID getClientUUID(); + + String getIdentityPublicKey(); + + long getClientId(); + + String getServerAddress(); + + String getDeviceModel(); + + int getDeviceOS(); + + String getGameVersion(); + + int getGuiScale(); + + String getLanguageCode(); + + String getXUID(); + + int getCurrentInputMode(); + + int getDefaultInputMode(); + + String getCapeData(); + + int getUIProfile(); +} diff --git a/src/main/java/cn/nukkit/utils/MainLogger.java b/src/main/java/cn/nukkit/utils/MainLogger.java index f03a6c16e2..25b2bc7836 100644 --- a/src/main/java/cn/nukkit/utils/MainLogger.java +++ b/src/main/java/cn/nukkit/utils/MainLogger.java @@ -99,7 +99,7 @@ public void debug(String message) { } public void setLogDebug(Boolean logDebug) { - this.logLevel = logDebug ? LogLevel.INFO : LogLevel.DEBUG; + this.logLevel = logDebug ? LogLevel.DEBUG : LogLevel.INFO; } public void logException(Exception e) { diff --git a/src/main/java/cn/nukkit/utils/MinecartType.java b/src/main/java/cn/nukkit/utils/MinecartType.java index e369644629..1bf3fb21de 100644 --- a/src/main/java/cn/nukkit/utils/MinecartType.java +++ b/src/main/java/cn/nukkit/utils/MinecartType.java @@ -1,13 +1,14 @@ package cn.nukkit.utils; import cn.nukkit.api.API; + import java.util.HashMap; import java.util.Map; /** * Helper class of Minecart variants *

- * By Adam Matthew + * By Adam Matthew * Creation time: 2017/7/17 19:55. */ @API(usage = API.Usage.STABLE, definition = API.Definition.INTERNAL) @@ -82,7 +83,7 @@ public int getId() { public String getName() { return realName; } - + /** * Gets if the minecart contains block * diff --git a/src/main/java/cn/nukkit/utils/Rail.java b/src/main/java/cn/nukkit/utils/Rail.java index 504d1d769d..7cb9d958e2 100644 --- a/src/main/java/cn/nukkit/utils/Rail.java +++ b/src/main/java/cn/nukkit/utils/Rail.java @@ -4,7 +4,10 @@ import cn.nukkit.block.Block; import cn.nukkit.math.BlockFace; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Stream; import static cn.nukkit.math.BlockFace.*; @@ -25,16 +28,16 @@ public static boolean isRailBlock(Block block) { } public enum Orientation { - STRAIGHT_NORTH_SOUTH (0, STRAIGHT, NORTH, SOUTH, null), - STRAIGHT_EAST_WEST (1, STRAIGHT, EAST, WEST, null), - ASCENDING_EAST (2, ASCENDING, EAST, WEST, EAST), - ASCENDING_WEST (3, ASCENDING, EAST, WEST, WEST), - ASCENDING_NORTH (4, ASCENDING, NORTH, SOUTH, NORTH), - ASCENDING_SOUTH (5, ASCENDING, NORTH, SOUTH, SOUTH), - CURVED_SOUTH_EAST (6, CURVED, SOUTH, EAST, null), - CURVED_SOUTH_WEST (7, CURVED, SOUTH, WEST, null), - CURVED_NORTH_WEST (8, CURVED, NORTH, WEST, null), - CURVED_NORTH_EAST (9, CURVED, NORTH, EAST, null); + STRAIGHT_NORTH_SOUTH(0, STRAIGHT, NORTH, SOUTH, null), + STRAIGHT_EAST_WEST(1, STRAIGHT, EAST, WEST, null), + ASCENDING_EAST(2, ASCENDING, EAST, WEST, EAST), + ASCENDING_WEST(3, ASCENDING, EAST, WEST, WEST), + ASCENDING_NORTH(4, ASCENDING, NORTH, SOUTH, NORTH), + ASCENDING_SOUTH(5, ASCENDING, NORTH, SOUTH, SOUTH), + CURVED_SOUTH_EAST(6, CURVED, SOUTH, EAST, null), + CURVED_SOUTH_WEST(7, CURVED, SOUTH, WEST, null), + CURVED_NORTH_WEST(8, CURVED, NORTH, WEST, null), + CURVED_NORTH_EAST(9, CURVED, NORTH, EAST, null); private static final Orientation[] META_LOOKUP = new Orientation[values().length]; private final int meta; diff --git a/src/main/java/cn/nukkit/utils/VarInt.java b/src/main/java/cn/nukkit/utils/VarInt.java index 373b3b07ea..e80f6fbbe4 100644 --- a/src/main/java/cn/nukkit/utils/VarInt.java +++ b/src/main/java/cn/nukkit/utils/VarInt.java @@ -20,9 +20,9 @@ @API(usage = EXPERIMENTAL, definition = UNIVERSAL) public final class VarInt { - private VarInt() { - //no instance - } + private VarInt() { + //no instance + } /** * @param v Signed int @@ -46,7 +46,7 @@ public static int decodeZigZag32(long v) { * @return Unsigned encoded long */ public static long encodeZigZag64(long v) { - return (v << 1) ^ (v >> 63); + return (v << 1) ^ (v >> 63); } /** @@ -58,31 +58,31 @@ public static long decodeZigZag64(long v) { } private static long read(BinaryStream stream, int maxSize) { - long value = 0; - int size = 0; - int b; - while (((b = stream.getByte()) & 0x80) == 0x80) { - value |= (long) (b & 0x7F) << (size++ * 7); - if (size >= maxSize) { - throw new IllegalArgumentException("VarLong too big"); - } - } + long value = 0; + int size = 0; + int b; + while (((b = stream.getByte()) & 0x80) == 0x80) { + value |= (long) (b & 0x7F) << (size++ * 7); + if (size >= maxSize) { + throw new IllegalArgumentException("VarLong too big"); + } + } - return value | ((long) (b & 0x7F) << (size * 7)); + return value | ((long) (b & 0x7F) << (size * 7)); } private static long read(InputStream stream, int maxSize) throws IOException { - long value = 0; - int size = 0; - int b; - while (((b = stream.read()) & 0x80) == 0x80) { - value |= (long) (b & 0x7F) << (size++ * 7); - if (size >= maxSize) { - throw new IllegalArgumentException("VarLong too big"); - } - } + long value = 0; + int size = 0; + int b; + while (((b = stream.read()) & 0x80) == 0x80) { + value |= (long) (b & 0x7F) << (size++ * 7); + if (size >= maxSize) { + throw new IllegalArgumentException("VarLong too big"); + } + } - return value | ((long) (b & 0x7F) << (size * 7)); + return value | ((long) (b & 0x7F) << (size * 7)); } /** @@ -150,27 +150,27 @@ public static long readUnsignedVarLong(InputStream stream) throws IOException { } private static void write(BinaryStream stream, long value) { - do { - byte temp = (byte)(value & 0b01111111); - // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone - value >>>= 7; - if (value != 0) { - temp |= 0b10000000; - } - stream.putByte(temp); - } while (value != 0); + do { + byte temp = (byte) (value & 0b01111111); + // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone + value >>>= 7; + if (value != 0) { + temp |= 0b10000000; + } + stream.putByte(temp); + } while (value != 0); } private static void write(OutputStream stream, long value) throws IOException { - do { - byte temp = (byte)(value & 0b01111111); - // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone - value >>>= 7; - if (value != 0) { - temp |= 0b10000000; - } - stream.write(temp); - } while (value != 0); + do { + byte temp = (byte) (value & 0b01111111); + // Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone + value >>>= 7; + if (value != 0) { + temp |= 0b10000000; + } + stream.write(temp); + } while (value != 0); } /** diff --git a/src/main/java/cn/nukkit/utils/Zlib.java b/src/main/java/cn/nukkit/utils/Zlib.java index fbf69bcb18..dc4347c73f 100644 --- a/src/main/java/cn/nukkit/utils/Zlib.java +++ b/src/main/java/cn/nukkit/utils/Zlib.java @@ -16,7 +16,7 @@ public static byte[] deflate(byte[] data) throws Exception { public static byte[] deflate(byte[] data, int level) throws Exception { Deflater deflater = getDef(level); - if(deflater == null) throw new IllegalArgumentException("No deflate for level "+level+" !"); + if (deflater == null) throw new IllegalArgumentException("No deflate for level " + level + " !"); deflater.reset(); deflater.setInput(data); deflater.finish(); @@ -65,7 +65,4 @@ private static byte[] inflate(InputStream stream) throws IOException { return buf.get(); } - - -} - +} \ No newline at end of file diff --git a/src/main/java/cn/nukkit/utils/completers/CommandsCompleter.java b/src/main/java/cn/nukkit/utils/completers/CommandsCompleter.java index 41e77e5ac1..30248759e4 100644 --- a/src/main/java/cn/nukkit/utils/completers/CommandsCompleter.java +++ b/src/main/java/cn/nukkit/utils/completers/CommandsCompleter.java @@ -1,13 +1,13 @@ package cn.nukkit.utils.completers; -import static jline.internal.Preconditions.checkNotNull; +import cn.nukkit.Server; +import jline.console.completer.Completer; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; -import cn.nukkit.Server; -import jline.console.completer.Completer; +import static jline.internal.Preconditions.checkNotNull; public class CommandsCompleter implements Completer { @@ -18,15 +18,14 @@ public int complete(String buffer, int cursor, List candidates) { if (buffer == null) { Server.getInstance().getCommandMap().getCommands().keySet().forEach((cmd) -> candidates.add(cmd)); - } - else { + } else { SortedSet names = new TreeSet(); Server.getInstance().getCommandMap().getCommands().keySet().forEach((cmd) -> names.add(cmd)); for (String match : names) { if (!match.toLowerCase().startsWith(buffer.toLowerCase())) { continue; } - + candidates.add(match); } } diff --git a/src/main/java/cn/nukkit/utils/completers/PlayersCompleter.java b/src/main/java/cn/nukkit/utils/completers/PlayersCompleter.java index 10930903b1..0c057dd91d 100644 --- a/src/main/java/cn/nukkit/utils/completers/PlayersCompleter.java +++ b/src/main/java/cn/nukkit/utils/completers/PlayersCompleter.java @@ -1,13 +1,13 @@ package cn.nukkit.utils.completers; -import static jline.internal.Preconditions.checkNotNull; +import cn.nukkit.Server; +import jline.console.completer.Completer; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; -import cn.nukkit.Server; -import jline.console.completer.Completer; +import static jline.internal.Preconditions.checkNotNull; public class PlayersCompleter implements Completer { @@ -18,8 +18,7 @@ public int complete(String buffer, int cursor, List candidates) { if (buffer == null) { Server.getInstance().getOnlinePlayers().values().forEach((p) -> candidates.add(p.getName())); - } - else { + } else { // We are auto completing player names, so 99% of the times we are doing this, it will be something like // "say John*TAB*" // however the buffer will be "say John", but we don't want that, the buffer must be the player's name @@ -33,7 +32,7 @@ public int complete(String buffer, int cursor, List candidates) { if (!match.toLowerCase().startsWith(buffer.toLowerCase())) { continue; } - + candidates.add(cmd + match); } } diff --git a/src/main/resources/creativeitems.json b/src/main/resources/creativeitems.json new file mode 100644 index 0000000000..9390ddb4f4 --- /dev/null +++ b/src/main/resources/creativeitems.json @@ -0,0 +1,3352 @@ +{ + "items": [ + { + "id": 5 + }, + { + "id": 5, + "damage": 1 + }, + { + "id": 5, + "damage": 2 + }, + { + "id": 5, + "damage": 3 + }, + { + "id": 5, + "damage": 4 + }, + { + "id": 5, + "damage": 5 + }, + { + "id": 139 + }, + { + "id": 139, + "damage": 1 + }, + { + "id": 85 + }, + { + "id": 85, + "damage": 1 + }, + { + "id": 85, + "damage": 2 + }, + { + "id": 85, + "damage": 3 + }, + { + "id": 85, + "damage": 4 + }, + { + "id": 85, + "damage": 5 + }, + { + "id": 113 + }, + { + "id": 107 + }, + { + "id": 183 + }, + { + "id": 184 + }, + { + "id": 185 + }, + { + "id": 187 + }, + { + "id": 186 + }, + { + "id": 67 + }, + { + "id": 53 + }, + { + "id": 134 + }, + { + "id": 135 + }, + { + "id": 136 + }, + { + "id": 163 + }, + { + "id": 164 + }, + { + "id": 108 + }, + { + "id": 109 + }, + { + "id": 114 + }, + { + "id": 128 + }, + { + "id": 180 + }, + { + "id": 156 + }, + { + "id": 203 + }, + { + "id": 324 + }, + { + "id": 427 + }, + { + "id": 428 + }, + { + "id": 429 + }, + { + "id": 430 + }, + { + "id": 431 + }, + { + "id": 330 + }, + { + "id": 96 + }, + { + "id": 167 + }, + { + "id": 101 + }, + { + "id": 20 + }, + { + "id": 241 + }, + { + "id": 241, + "damage": 8 + }, + { + "id": 241, + "damage": 7 + }, + { + "id": 241, + "damage": 15 + }, + { + "id": 241, + "damage": 12 + }, + { + "id": 241, + "damage": 14 + }, + { + "id": 241, + "damage": 1 + }, + { + "id": 241, + "damage": 4 + }, + { + "id": 241, + "damage": 5 + }, + { + "id": 241, + "damage": 13 + }, + { + "id": 241, + "damage": 9 + }, + { + "id": 241, + "damage": 3 + }, + { + "id": 241, + "damage": 11 + }, + { + "id": 241, + "damage": 10 + }, + { + "id": 241, + "damage": 2 + }, + { + "id": 241, + "damage": 6 + }, + { + "id": 102 + }, + { + "id": 160 + }, + { + "id": 160, + "damage": 8 + }, + { + "id": 160, + "damage": 7 + }, + { + "id": 160, + "damage": 15 + }, + { + "id": 160, + "damage": 12 + }, + { + "id": 160, + "damage": 14 + }, + { + "id": 160, + "damage": 1 + }, + { + "id": 160, + "damage": 4 + }, + { + "id": 160, + "damage": 5 + }, + { + "id": 160, + "damage": 13 + }, + { + "id": 160, + "damage": 9 + }, + { + "id": 160, + "damage": 3 + }, + { + "id": 160, + "damage": 11 + }, + { + "id": 160, + "damage": 10 + }, + { + "id": 160, + "damage": 2 + }, + { + "id": 160, + "damage": 6 + }, + { + "id": 65 + }, + { + "id": 44 + }, + { + "id": 44, + "damage": 3 + }, + { + "id": 158 + }, + { + "id": 158, + "damage": 1 + }, + { + "id": 158, + "damage": 2 + }, + { + "id": 158, + "damage": 3 + }, + { + "id": 158, + "damage": 4 + }, + { + "id": 158, + "damage": 5 + }, + { + "id": 44, + "damage": 4 + }, + { + "id": 44, + "damage": 5 + }, + { + "id": 44, + "damage": 7 + }, + { + "id": 44, + "damage": 1 + }, + { + "id": 182 + }, + { + "id": 44, + "damage": 6 + }, + { + "id": 182, + "damage": 1 + }, + { + "id": 45 + }, + { + "id": 98 + }, + { + "id": 98, + "damage": 1 + }, + { + "id": 98, + "damage": 2 + }, + { + "id": 98, + "damage": 3 + }, + { + "id": 206 + }, + { + "id": 168, + "damage": 2 + }, + { + "id": 112 + }, + { + "id": 215 + }, + { + "id": 4 + }, + { + "id": 48 + }, + { + "id": 406 + }, + { + "id": 24 + }, + { + "id": 24, + "damage": 1 + }, + { + "id": 24, + "damage": 2 + }, + { + "id": 179 + }, + { + "id": 179, + "damage": 1 + }, + { + "id": 179, + "damage": 2 + }, + { + "id": 173 + }, + { + "id": 152 + }, + { + "id": 41 + }, + { + "id": 42 + }, + { + "id": 133 + }, + { + "id": 57 + }, + { + "id": 22 + }, + { + "id": 155 + }, + { + "id": 155, + "damage": 2 + }, + { + "id": 155, + "damage": 1 + }, + { + "id": 168 + }, + { + "id": 168, + "damage": 1 + }, + { + "id": 165 + }, + { + "id": 170 + }, + { + "id": 216 + }, + { + "id": 214 + }, + { + "id": 35 + }, + { + "id": 35, + "damage": 8 + }, + { + "id": 35, + "damage": 7 + }, + { + "id": 35, + "damage": 15 + }, + { + "id": 35, + "damage": 12 + }, + { + "id": 35, + "damage": 14 + }, + { + "id": 35, + "damage": 1 + }, + { + "id": 35, + "damage": 4 + }, + { + "id": 35, + "damage": 5 + }, + { + "id": 35, + "damage": 13 + }, + { + "id": 35, + "damage": 9 + }, + { + "id": 35, + "damage": 3 + }, + { + "id": 35, + "damage": 11 + }, + { + "id": 35, + "damage": 10 + }, + { + "id": 35, + "damage": 2 + }, + { + "id": 35, + "damage": 6 + }, + { + "id": 171 + }, + { + "id": 171, + "damage": 8 + }, + { + "id": 171, + "damage": 7 + }, + { + "id": 171, + "damage": 15 + }, + { + "id": 171, + "damage": 12 + }, + { + "id": 171, + "damage": 14 + }, + { + "id": 171, + "damage": 1 + }, + { + "id": 171, + "damage": 4 + }, + { + "id": 171, + "damage": 5 + }, + { + "id": 171, + "damage": 13 + }, + { + "id": 171, + "damage": 9 + }, + { + "id": 171, + "damage": 3 + }, + { + "id": 171, + "damage": 11 + }, + { + "id": 171, + "damage": 10 + }, + { + "id": 171, + "damage": 2 + }, + { + "id": 171, + "damage": 6 + }, + { + "id": 237 + }, + { + "id": 237, + "damage": 8 + }, + { + "id": 237, + "damage": 7 + }, + { + "id": 237, + "damage": 15 + }, + { + "id": 237, + "damage": 12 + }, + { + "id": 237, + "damage": 14 + }, + { + "id": 237, + "damage": 1 + }, + { + "id": 237, + "damage": 4 + }, + { + "id": 237, + "damage": 5 + }, + { + "id": 237, + "damage": 13 + }, + { + "id": 237, + "damage": 9 + }, + { + "id": 237, + "damage": 3 + }, + { + "id": 237, + "damage": 11 + }, + { + "id": 237, + "damage": 10 + }, + { + "id": 237, + "damage": 2 + }, + { + "id": 237, + "damage": 6 + }, + { + "id": 236 + }, + { + "id": 236, + "damage": 8 + }, + { + "id": 236, + "damage": 7 + }, + { + "id": 236, + "damage": 15 + }, + { + "id": 236, + "damage": 12 + }, + { + "id": 236, + "damage": 14 + }, + { + "id": 236, + "damage": 1 + }, + { + "id": 236, + "damage": 4 + }, + { + "id": 236, + "damage": 5 + }, + { + "id": 236, + "damage": 13 + }, + { + "id": 236, + "damage": 9 + }, + { + "id": 236, + "damage": 3 + }, + { + "id": 236, + "damage": 11 + }, + { + "id": 236, + "damage": 10 + }, + { + "id": 236, + "damage": 2 + }, + { + "id": 236, + "damage": 6 + }, + { + "id": 82 + }, + { + "id": 172 + }, + { + "id": 159 + }, + { + "id": 159, + "damage": 8 + }, + { + "id": 159, + "damage": 7 + }, + { + "id": 159, + "damage": 15 + }, + { + "id": 159, + "damage": 12 + }, + { + "id": 159, + "damage": 14 + }, + { + "id": 159, + "damage": 1 + }, + { + "id": 159, + "damage": 4 + }, + { + "id": 159, + "damage": 5 + }, + { + "id": 159, + "damage": 13 + }, + { + "id": 159, + "damage": 9 + }, + { + "id": 159, + "damage": 3 + }, + { + "id": 159, + "damage": 11 + }, + { + "id": 159, + "damage": 10 + }, + { + "id": 159, + "damage": 2 + }, + { + "id": 159, + "damage": 6 + }, + { + "id": 220 + }, + { + "id": 228 + }, + { + "id": 227 + }, + { + "id": 235 + }, + { + "id": 232 + }, + { + "id": 234 + }, + { + "id": 221 + }, + { + "id": 224 + }, + { + "id": 225 + }, + { + "id": 233 + }, + { + "id": 229 + }, + { + "id": 223 + }, + { + "id": 231 + }, + { + "id": 219 + }, + { + "id": 222 + }, + { + "id": 226 + }, + { + "id": 201 + }, + { + "id": 201, + "damage": 2 + }, + { + "id": 3 + }, + { + "id": 3, + "damage": 1 + }, + { + "id": 2 + }, + { + "id": 243 + }, + { + "id": 110 + }, + { + "id": 1 + }, + { + "id": 15 + }, + { + "id": 14 + }, + { + "id": 56 + }, + { + "id": 21 + }, + { + "id": 73 + }, + { + "id": 16 + }, + { + "id": 129 + }, + { + "id": 153 + }, + { + "id": 13 + }, + { + "id": 1, + "damage": 1 + }, + { + "id": 1, + "damage": 3 + }, + { + "id": 1, + "damage": 5 + }, + { + "id": 1, + "damage": 2 + }, + { + "id": 1, + "damage": 4 + }, + { + "id": 1, + "damage": 6 + }, + { + "id": 12 + }, + { + "id": 12, + "damage": 1 + }, + { + "id": 81 + }, + { + "id": 17 + }, + { + "id": 17, + "damage": 1 + }, + { + "id": 17, + "damage": 2 + }, + { + "id": 17, + "damage": 3 + }, + { + "id": 162 + }, + { + "id": 162, + "damage": 1 + }, + { + "id": 18 + }, + { + "id": 18, + "damage": 1 + }, + { + "id": 18, + "damage": 2 + }, + { + "id": 18, + "damage": 3 + }, + { + "id": 161 + }, + { + "id": 161, + "damage": 1 + }, + { + "id": 6 + }, + { + "id": 6, + "damage": 1 + }, + { + "id": 6, + "damage": 2 + }, + { + "id": 6, + "damage": 3 + }, + { + "id": 6, + "damage": 4 + }, + { + "id": 6, + "damage": 5 + }, + { + "id": 295 + }, + { + "id": 361 + }, + { + "id": 362 + }, + { + "id": 458 + }, + { + "id": 296 + }, + { + "id": 457 + }, + { + "id": 392 + }, + { + "id": 394 + }, + { + "id": 391 + }, + { + "id": 396 + }, + { + "id": 260 + }, + { + "id": 322 + }, + { + "id": 466 + }, + { + "id": 103 + }, + { + "id": 360 + }, + { + "id": 382 + }, + { + "id": 86 + }, + { + "id": 91 + }, + { + "id": 31, + "damage": 2 + }, + { + "id": 175, + "damage": 3 + }, + { + "id": 31, + "damage": 1 + }, + { + "id": 175, + "damage": 2 + }, + { + "id": 37 + }, + { + "id": 38 + }, + { + "id": 38, + "damage": 1 + }, + { + "id": 38, + "damage": 2 + }, + { + "id": 38, + "damage": 3 + }, + { + "id": 38, + "damage": 4 + }, + { + "id": 38, + "damage": 5 + }, + { + "id": 38, + "damage": 6 + }, + { + "id": 38, + "damage": 7 + }, + { + "id": 38, + "damage": 8 + }, + { + "id": 175 + }, + { + "id": 175, + "damage": 1 + }, + { + "id": 175, + "damage": 4 + }, + { + "id": 175, + "damage": 5 + }, + { + "id": 351, + "damage": 7 + }, + { + "id": 351, + "damage": 8 + }, + { + "id": 351 + }, + { + "id": 351, + "damage": 1 + }, + { + "id": 351, + "damage": 14 + }, + { + "id": 351, + "damage": 11 + }, + { + "id": 351, + "damage": 10 + }, + { + "id": 351, + "damage": 2 + }, + { + "id": 351, + "damage": 6 + }, + { + "id": 351, + "damage": 12 + }, + { + "id": 351, + "damage": 4 + }, + { + "id": 351, + "damage": 5 + }, + { + "id": 351, + "damage": 13 + }, + { + "id": 351, + "damage": 9 + }, + { + "id": 351, + "damage": 15 + }, + { + "id": 351, + "damage": 3 + }, + { + "id": 106 + }, + { + "id": 111 + }, + { + "id": 32 + }, + { + "id": 80 + }, + { + "id": 79 + }, + { + "id": 174 + }, + { + "id": 78 + }, + { + "id": 365 + }, + { + "id": 319 + }, + { + "id": 363 + }, + { + "id": 423 + }, + { + "id": 411 + }, + { + "id": 349 + }, + { + "id": 460 + }, + { + "id": 461 + }, + { + "id": 462 + }, + { + "id": 366 + }, + { + "id": 320 + }, + { + "id": 364 + }, + { + "id": 424 + }, + { + "id": 412 + }, + { + "id": 350 + }, + { + "id": 463 + }, + { + "id": 297 + }, + { + "id": 282 + }, + { + "id": 459 + }, + { + "id": 413 + }, + { + "id": 393 + }, + { + "id": 357 + }, + { + "id": 400 + }, + { + "id": 354 + }, + { + "id": 39 + }, + { + "id": 40 + }, + { + "id": 99, + "damage": 14 + }, + { + "id": 100, + "damage": 14 + }, + { + "id": 99, + "damage": 15 + }, + { + "id": 99 + }, + { + "id": 344 + }, + { + "id": 338 + }, + { + "id": 353 + }, + { + "id": 52 + }, + { + "id": 97 + }, + { + "id": 97, + "damage": 1 + }, + { + "id": 97, + "damage": 2 + }, + { + "id": 97, + "damage": 3 + }, + { + "id": 97, + "damage": 4 + }, + { + "id": 97, + "damage": 5 + }, + { + "id": 122 + }, + { + "id": 383, + "damage": 10 + }, + { + "id": 383, + "damage": 11 + }, + { + "id": 383, + "damage": 12 + }, + { + "id": 383, + "damage": 13 + }, + { + "id": 383, + "damage": 14 + }, + { + "id": 383, + "damage": 28 + }, + { + "id": 383, + "damage": 22 + }, + { + "id": 383, + "damage": 16 + }, + { + "id": 383, + "damage": 19 + }, + { + "id": 383, + "damage": 30 + }, + { + "id": 383, + "damage": 18 + }, + { + "id": 383, + "damage": 29 + }, + { + "id": 383, + "damage": 23 + }, + { + "id": 383, + "damage": 24 + }, + { + "id": 383, + "damage": 25 + }, + { + "id": 383, + "damage": 26 + }, + { + "id": 383, + "damage": 27 + }, + { + "id": 383, + "damage": 33 + }, + { + "id": 383, + "damage": 38 + }, + { + "id": 383, + "damage": 39 + }, + { + "id": 383, + "damage": 34 + }, + { + "id": 383, + "damage": 48 + }, + { + "id": 383, + "damage": 46 + }, + { + "id": 383, + "damage": 37 + }, + { + "id": 383, + "damage": 35 + }, + { + "id": 383, + "damage": 32 + }, + { + "id": 383, + "damage": 36 + }, + { + "id": 383, + "damage": 47 + }, + { + "id": 383, + "damage": 17 + }, + { + "id": 383, + "damage": 40 + }, + { + "id": 383, + "damage": 45 + }, + { + "id": 383, + "damage": 49 + }, + { + "id": 383, + "damage": 50 + }, + { + "id": 383, + "damage": 55 + }, + { + "id": 383, + "damage": 42 + }, + { + "id": 383, + "damage": 41 + }, + { + "id": 383, + "damage": 43 + }, + { + "id": 383, + "damage": 54 + }, + { + "id": 383, + "damage": 57 + }, + { + "id": 383, + "damage": 104 + }, + { + "id": 383, + "damage": 105 + }, + { + "id": 383, + "damage": 15 + }, + { + "id": 383, + "damage": 44 + }, + { + "id": 49 + }, + { + "id": 7 + }, + { + "id": 88 + }, + { + "id": 87 + }, + { + "id": 213 + }, + { + "id": 372 + }, + { + "id": 121 + }, + { + "id": 200 + }, + { + "id": 240 + }, + { + "id": 432 + }, + { + "id": 433 + }, + { + "id": 19 + }, + { + "id": 19, + "damage": 1 + }, + { + "id": 367 + }, + { + "id": 352 + }, + { + "id": 30 + }, + { + "id": 298 + }, + { + "id": 302 + }, + { + "id": 306 + }, + { + "id": 314 + }, + { + "id": 310 + }, + { + "id": 299 + }, + { + "id": 303 + }, + { + "id": 307 + }, + { + "id": 315 + }, + { + "id": 311 + }, + { + "id": 300 + }, + { + "id": 304 + }, + { + "id": 308 + }, + { + "id": 316 + }, + { + "id": 312 + }, + { + "id": 301 + }, + { + "id": 305 + }, + { + "id": 309 + }, + { + "id": 317 + }, + { + "id": 313 + }, + { + "id": 329 + }, + { + "id": 416 + }, + { + "id": 417 + }, + { + "id": 418 + }, + { + "id": 419 + }, + { + "id": 444 + }, + { + "id": 268 + }, + { + "id": 272 + }, + { + "id": 267 + }, + { + "id": 283 + }, + { + "id": 276 + }, + { + "id": 271 + }, + { + "id": 275 + }, + { + "id": 258 + }, + { + "id": 286 + }, + { + "id": 279 + }, + { + "id": 270 + }, + { + "id": 274 + }, + { + "id": 257 + }, + { + "id": 285 + }, + { + "id": 278 + }, + { + "id": 269 + }, + { + "id": 273 + }, + { + "id": 256 + }, + { + "id": 284 + }, + { + "id": 277 + }, + { + "id": 290 + }, + { + "id": 291 + }, + { + "id": 292 + }, + { + "id": 294 + }, + { + "id": 293 + }, + { + "id": 261 + }, + { + "id": 262 + }, + { + "id": 262, + "damage": 6 + }, + { + "id": 262, + "damage": 7 + }, + { + "id": 262, + "damage": 8 + }, + { + "id": 262, + "damage": 9 + }, + { + "id": 262, + "damage": 10 + }, + { + "id": 262, + "damage": 11 + }, + { + "id": 262, + "damage": 12 + }, + { + "id": 262, + "damage": 13 + }, + { + "id": 262, + "damage": 14 + }, + { + "id": 262, + "damage": 15 + }, + { + "id": 262, + "damage": 16 + }, + { + "id": 262, + "damage": 17 + }, + { + "id": 262, + "damage": 18 + }, + { + "id": 262, + "damage": 19 + }, + { + "id": 262, + "damage": 20 + }, + { + "id": 262, + "damage": 21 + }, + { + "id": 262, + "damage": 22 + }, + { + "id": 262, + "damage": 23 + }, + { + "id": 262, + "damage": 24 + }, + { + "id": 262, + "damage": 25 + }, + { + "id": 262, + "damage": 26 + }, + { + "id": 262, + "damage": 27 + }, + { + "id": 262, + "damage": 28 + }, + { + "id": 262, + "damage": 29 + }, + { + "id": 262, + "damage": 30 + }, + { + "id": 262, + "damage": 31 + }, + { + "id": 262, + "damage": 32 + }, + { + "id": 262, + "damage": 33 + }, + { + "id": 262, + "damage": 34 + }, + { + "id": 262, + "damage": 35 + }, + { + "id": 262, + "damage": 36 + }, + { + "id": 262, + "damage": 37 + }, + { + "id": 346 + }, + { + "id": 398 + }, + { + "id": 332 + }, + { + "id": 359 + }, + { + "id": 259 + }, + { + "id": 450 + }, + { + "id": 374 + }, + { + "id": 384 + }, + { + "id": 373 + }, + { + "id": 373, + "damage": 1 + }, + { + "id": 373, + "damage": 2 + }, + { + "id": 373, + "damage": 3 + }, + { + "id": 373, + "damage": 4 + }, + { + "id": 373, + "damage": 5 + }, + { + "id": 373, + "damage": 6 + }, + { + "id": 373, + "damage": 7 + }, + { + "id": 373, + "damage": 8 + }, + { + "id": 373, + "damage": 9 + }, + { + "id": 373, + "damage": 10 + }, + { + "id": 373, + "damage": 11 + }, + { + "id": 373, + "damage": 12 + }, + { + "id": 373, + "damage": 13 + }, + { + "id": 373, + "damage": 14 + }, + { + "id": 373, + "damage": 15 + }, + { + "id": 373, + "damage": 16 + }, + { + "id": 373, + "damage": 17 + }, + { + "id": 373, + "damage": 18 + }, + { + "id": 373, + "damage": 19 + }, + { + "id": 373, + "damage": 20 + }, + { + "id": 373, + "damage": 21 + }, + { + "id": 373, + "damage": 22 + }, + { + "id": 373, + "damage": 23 + }, + { + "id": 373, + "damage": 24 + }, + { + "id": 373, + "damage": 25 + }, + { + "id": 373, + "damage": 26 + }, + { + "id": 373, + "damage": 27 + }, + { + "id": 373, + "damage": 28 + }, + { + "id": 373, + "damage": 29 + }, + { + "id": 373, + "damage": 30 + }, + { + "id": 373, + "damage": 31 + }, + { + "id": 373, + "damage": 32 + }, + { + "id": 373, + "damage": 33 + }, + { + "id": 373, + "damage": 34 + }, + { + "id": 373, + "damage": 35 + }, + { + "id": 373, + "damage": 36 + }, + { + "id": 438 + }, + { + "id": 438, + "damage": 1 + }, + { + "id": 438, + "damage": 2 + }, + { + "id": 438, + "damage": 3 + }, + { + "id": 438, + "damage": 4 + }, + { + "id": 438, + "damage": 5 + }, + { + "id": 438, + "damage": 6 + }, + { + "id": 438, + "damage": 7 + }, + { + "id": 438, + "damage": 8 + }, + { + "id": 438, + "damage": 9 + }, + { + "id": 438, + "damage": 10 + }, + { + "id": 438, + "damage": 11 + }, + { + "id": 438, + "damage": 12 + }, + { + "id": 438, + "damage": 13 + }, + { + "id": 438, + "damage": 14 + }, + { + "id": 438, + "damage": 15 + }, + { + "id": 438, + "damage": 16 + }, + { + "id": 438, + "damage": 17 + }, + { + "id": 438, + "damage": 18 + }, + { + "id": 438, + "damage": 19 + }, + { + "id": 438, + "damage": 20 + }, + { + "id": 438, + "damage": 21 + }, + { + "id": 438, + "damage": 22 + }, + { + "id": 438, + "damage": 23 + }, + { + "id": 438, + "damage": 24 + }, + { + "id": 438, + "damage": 25 + }, + { + "id": 438, + "damage": 26 + }, + { + "id": 438, + "damage": 27 + }, + { + "id": 438, + "damage": 28 + }, + { + "id": 438, + "damage": 29 + }, + { + "id": 438, + "damage": 30 + }, + { + "id": 438, + "damage": 31 + }, + { + "id": 438, + "damage": 32 + }, + { + "id": 438, + "damage": 33 + }, + { + "id": 438, + "damage": 34 + }, + { + "id": 438, + "damage": 35 + }, + { + "id": 438, + "damage": 36 + }, + { + "id": 441 + }, + { + "id": 441, + "damage": 1 + }, + { + "id": 441, + "damage": 2 + }, + { + "id": 441, + "damage": 3 + }, + { + "id": 441, + "damage": 4 + }, + { + "id": 441, + "damage": 5 + }, + { + "id": 441, + "damage": 6 + }, + { + "id": 441, + "damage": 7 + }, + { + "id": 441, + "damage": 8 + }, + { + "id": 441, + "damage": 9 + }, + { + "id": 441, + "damage": 10 + }, + { + "id": 441, + "damage": 11 + }, + { + "id": 441, + "damage": 12 + }, + { + "id": 441, + "damage": 13 + }, + { + "id": 441, + "damage": 14 + }, + { + "id": 441, + "damage": 15 + }, + { + "id": 441, + "damage": 16 + }, + { + "id": 441, + "damage": 17 + }, + { + "id": 441, + "damage": 18 + }, + { + "id": 441, + "damage": 19 + }, + { + "id": 441, + "damage": 20 + }, + { + "id": 441, + "damage": 21 + }, + { + "id": 441, + "damage": 22 + }, + { + "id": 441, + "damage": 23 + }, + { + "id": 441, + "damage": 24 + }, + { + "id": 441, + "damage": 25 + }, + { + "id": 441, + "damage": 26 + }, + { + "id": 441, + "damage": 27 + }, + { + "id": 441, + "damage": 28 + }, + { + "id": 441, + "damage": 29 + }, + { + "id": 441, + "damage": 30 + }, + { + "id": 441, + "damage": 31 + }, + { + "id": 441, + "damage": 32 + }, + { + "id": 441, + "damage": 33 + }, + { + "id": 441, + "damage": 34 + }, + { + "id": 441, + "damage": 35 + }, + { + "id": 441, + "damage": 36 + }, + { + "id": 280 + }, + { + "id": 355 + }, + { + "id": 355, + "damage": 8 + }, + { + "id": 355, + "damage": 7 + }, + { + "id": 355, + "damage": 15 + }, + { + "id": 355, + "damage": 12 + }, + { + "id": 355, + "damage": 14 + }, + { + "id": 355, + "damage": 1 + }, + { + "id": 355, + "damage": 4 + }, + { + "id": 355, + "damage": 5 + }, + { + "id": 355, + "damage": 13 + }, + { + "id": 355, + "damage": 9 + }, + { + "id": 355, + "damage": 3 + }, + { + "id": 355, + "damage": 11 + }, + { + "id": 355, + "damage": 10 + }, + { + "id": 355, + "damage": 2 + }, + { + "id": 355, + "damage": 6 + }, + { + "id": 50 + }, + { + "id": 76 + }, + { + "id": 123 + }, + { + "id": 169 + }, + { + "id": 89 + }, + { + "id": 348 + }, + { + "id": 323 + }, + { + "id": 321 + }, + { + "id": 389 + }, + { + "id": 390 + }, + { + "id": 281 + }, + { + "id": 425 + }, + { + "id": 58 + }, + { + "id": 61 + }, + { + "id": 379 + }, + { + "id": 380 + }, + { + "id": 145 + }, + { + "id": 145, + "damage": 1 + }, + { + "id": 145, + "damage": 2 + }, + { + "id": 245 + }, + { + "id": 54 + }, + { + "id": 146 + }, + { + "id": 130 + }, + { + "id": 205, + "damage": 16 + }, + { + "id": 218 + }, + { + "id": 218, + "damage": 8 + }, + { + "id": 218, + "damage": 7 + }, + { + "id": 218, + "damage": 15 + }, + { + "id": 218, + "damage": 12 + }, + { + "id": 218, + "damage": 14 + }, + { + "id": 218, + "damage": 1 + }, + { + "id": 218, + "damage": 4 + }, + { + "id": 218, + "damage": 5 + }, + { + "id": 218, + "damage": 13 + }, + { + "id": 218, + "damage": 9 + }, + { + "id": 218, + "damage": 3 + }, + { + "id": 218, + "damage": 11 + }, + { + "id": 218, + "damage": 10 + }, + { + "id": 218, + "damage": 2 + }, + { + "id": 218, + "damage": 6 + }, + { + "id": 47 + }, + { + "id": 116 + }, + { + "id": 25 + }, + { + "id": 84 + }, + { + "id": 500 + }, + { + "id": 501 + }, + { + "id": 502 + }, + { + "id": 503 + }, + { + "id": 504 + }, + { + "id": 505 + }, + { + "id": 506 + }, + { + "id": 507 + }, + { + "id": 508 + }, + { + "id": 509 + }, + { + "id": 510 + }, + { + "id": 511 + }, + { + "id": 397, + "damage": 3 + }, + { + "id": 397, + "damage": 2 + }, + { + "id": 397, + "damage": 4 + }, + { + "id": 397, + "damage": 5 + }, + { + "id": 397 + }, + { + "id": 397, + "damage": 1 + }, + { + "id": 138 + }, + { + "id": 151 + }, + { + "id": 120 + }, + { + "id": 287 + }, + { + "id": 325 + }, + { + "id": 325, + "damage": 1 + }, + { + "id": 325, + "damage": 8 + }, + { + "id": 325, + "damage": 10 + }, + { + "id": 288 + }, + { + "id": 318 + }, + { + "id": 289 + }, + { + "id": 334 + }, + { + "id": 415 + }, + { + "id": 414 + }, + { + "id": 452 + }, + { + "id": 371 + }, + { + "id": 385 + }, + { + "id": 377 + }, + { + "id": 369 + }, + { + "id": 378 + }, + { + "id": 375 + }, + { + "id": 376 + }, + { + "id": 437 + }, + { + "id": 445 + }, + { + "id": 370 + }, + { + "id": 341 + }, + { + "id": 368 + }, + { + "id": 381 + }, + { + "id": 399 + }, + { + "id": 208 + }, + { + "id": 426 + }, + { + "id": 339 + }, + { + "id": 395 + }, + { + "id": 395, + "damage": 2 + }, + { + "id": 386 + }, + { + "id": 340 + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696400000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696400000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696400000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696400000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696401000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696401000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696401000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696401000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696402000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696402000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696402000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696402000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696403000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696403000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696403000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696403000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696404000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696404000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696404000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696404000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696405000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696405000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696405000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696406000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696406000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696406000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696407000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696407000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696407000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696408000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696409000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696409000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696409000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696409000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696409000203006c766c05000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640a000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640a000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640a000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640a000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640a000203006c766c05000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640b000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640b000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640b000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640b000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640b000203006c766c05000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640c000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640c000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640d000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640d000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640e000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640e000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640e000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640f000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640f000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640f000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640f000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069640f000203006c766c05000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696410000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696411000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696411000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696411000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696412000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696412000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696412000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696413000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696413000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696413000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696413000203006c766c04000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696413000203006c766c05000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696414000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696414000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696415000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696416000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696417000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696417000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696417000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696418000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696418000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696418000203006c766c03000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696419000203006c766c01000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a01000000020200696419000203006c766c02000000" + }, + { + "id": 403, + "nbt_hex": "0a0000090400656e63680a0100000002020069641a000203006c766c01000000" + }, + { + "id": 333 + }, + { + "id": 333, + "damage": 1 + }, + { + "id": 333, + "damage": 2 + }, + { + "id": 333, + "damage": 3 + }, + { + "id": 333, + "damage": 4 + }, + { + "id": 333, + "damage": 5 + }, + { + "id": 66 + }, + { + "id": 27 + }, + { + "id": 28 + }, + { + "id": 126 + }, + { + "id": 328 + }, + { + "id": 342 + }, + { + "id": 408 + }, + { + "id": 407 + }, + { + "id": 69 + }, + { + "id": 143, + "damage": 5 + }, + { + "id": 77, + "damage": 5 + }, + { + "id": 410 + }, + { + "id": 125, + "damage": 3 + }, + { + "id": 23, + "damage": 3 + }, + { + "id": 33, + "damage": 1 + }, + { + "id": 29, + "damage": 1 + }, + { + "id": 251 + }, + { + "id": 356 + }, + { + "id": 404 + }, + { + "id": 131 + }, + { + "id": 72 + }, + { + "id": 70 + }, + { + "id": 147 + }, + { + "id": 148 + }, + { + "id": 331 + }, + { + "id": 263 + }, + { + "id": 263, + "damage": 1 + }, + { + "id": 264 + }, + { + "id": 265 + }, + { + "id": 266 + }, + { + "id": 388 + }, + { + "id": 336 + }, + { + "id": 405 + }, + { + "id": 337 + }, + { + "id": 409 + }, + { + "id": 422 + }, + { + "id": 46 + }, + { + "id": 420 + }, + { + "id": 421 + }, + { + "id": 347 + }, + { + "id": 345 + }, + { + "id": 446 + }, + { + "id": 446, + "damage": 8 + }, + { + "id": 446, + "damage": 7 + }, + { + "id": 446, + "damage": 15 + }, + { + "id": 446, + "damage": 12 + }, + { + "id": 446, + "damage": 14 + }, + { + "id": 446, + "damage": 1 + }, + { + "id": 446, + "damage": 4 + }, + { + "id": 446, + "damage": 5 + }, + { + "id": 446, + "damage": 13 + }, + { + "id": 446, + "damage": 9 + }, + { + "id": 446, + "damage": 3 + }, + { + "id": 446, + "damage": 11 + }, + { + "id": 446, + "damage": 10 + }, + { + "id": 446, + "damage": 2 + }, + { + "id": 446, + "damage": 6 + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730000000000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000000070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000008070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000007070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f72010000000f070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f72010000000c070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f72010000000e070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000001070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000004070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000005070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f72010000000d070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000009070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000003070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f72010000000b070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f72010000000a070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000002070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 401, + "nbt_hex": "0a00000a090046697265776f726b73090a004578706c6f73696f6e730a01000000070d0046697265776f726b436f6c6f720100000006070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000010600466c69676874010000" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000000070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72211d1dff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000008070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72524f47ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000007070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72979d9dff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f72010000000f070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72f0f0f0ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f72010000000c070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72dab33aff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f72010000000e070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f721d80f9ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000001070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72262eb0ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000004070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72aa443cff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000005070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72b83289ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f72010000000d070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72bd4ec7ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000009070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72aa8bf3ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000003070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72325483ff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f72010000000b070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f723dd8feff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f72010000000a070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f721fc780ff00" + }, + { + "id": 402, + "c": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000002070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f72167c5eff00" + }, + { + "id": 402, + "nbt_hex": "0a00000a0d0046697265776f726b734974656d070d0046697265776f726b436f6c6f720100000006070c0046697265776f726b4661646500000000010f0046697265776f726b466c69636b657200010d0046697265776f726b547261696c00010c0046697265776f726b547970650000030b00637573746f6d436f6c6f729c9c16ff00" + } + ] +} \ No newline at end of file diff --git a/src/test/java/cn/nukkit/test/ClientChainDataTest.java b/src/test/java/cn/nukkit/test/ClientChainDataTest.java index 09476116e6..a6cec4b87e 100644 --- a/src/test/java/cn/nukkit/test/ClientChainDataTest.java +++ b/src/test/java/cn/nukkit/test/ClientChainDataTest.java @@ -30,8 +30,7 @@ void testGetter() throws Exception { "deviceOS=%d, gameVersion=%s, " + "guiScale=%d, languageCode=%s, " + "xuid=%s, currentInputMode=%d, " + - "defaultInputMode=%d, ADRole=%s," + - "tenantId=%s, UIProfile=%d" + "defaultInputMode=%d, UIProfile=%d" , data.getUsername(), data.getClientUUID(), data.getIdentityPublicKey(), data.getClientId(), @@ -39,8 +38,7 @@ void testGetter() throws Exception { data.getDeviceOS(), data.getGameVersion(), data.getGuiScale(), data.getLanguageCode(), data.getXUID(), data.getCurrentInputMode(), - data.getDefaultInputMode(), data.getADRole(), - data.getTenantId(), data.getUIProfile() + data.getDefaultInputMode(), data.getUIProfile() ); String expecting = "userName=lmlstarqaq, clientUUID=8323afe1-641e-3b61-9a92-d5d20b279065, " + "identityPublicKey=MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE4lyvA1iVhV2u3pLQqJAjJnJZSlSjib8mM1uB5h5yqOBSvCHW+nZxDmkOAW6MS1GA7yGHitGmfS4jW/yUISUdWvLzEWJYOzphb3GNh5J1oLJRwESc5278i4MEDk1y21/q, " + @@ -49,8 +47,7 @@ void testGetter() throws Exception { "deviceOS=2, gameVersion=1.1.0, " + "guiScale=0, languageCode=zh_CN, " + "xuid=2535465134455915, currentInputMode=2, " + - "defaultInputMode=2, ADRole=2,tenantId=, " + - "UIProfile=1"; + "defaultInputMode=2, UIProfile=1"; assertEquals(got, expecting); }