diff --git a/src/main/java/com/darkona/adventurebackpack/block/BlockSleepingBag.java b/src/main/java/com/darkona/adventurebackpack/block/BlockSleepingBag.java index 8a8e7075..b6ba3954 100644 --- a/src/main/java/com/darkona/adventurebackpack/block/BlockSleepingBag.java +++ b/src/main/java/com/darkona/adventurebackpack/block/BlockSleepingBag.java @@ -10,7 +10,6 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.init.Blocks; import net.minecraft.item.Item; -import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.Direction; @@ -36,11 +35,6 @@ public class BlockSleepingBag extends BlockDirectional { private static final int[][] footBlockToHeadBlockMap = new int[][] { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; - private static final String TAG_STORED_SPAWN = "storedSpawn"; - private static final String TAG_SPAWN_POS_X = "posX"; - private static final String TAG_SPAWN_POS_Y = "posY"; - private static final String TAG_SPAWN_POS_Z = "posZ"; - @SideOnly(Side.CLIENT) private IIcon[] endIcons; @@ -79,6 +73,15 @@ private static boolean isBlockHeadOfBed(int meta) { return (meta & 8) != 0; } + private static ChunkCoordinates getHeadCoordinates(int x, int y, int z, int meta) { + if (!isBlockHeadOfBed(meta)) { + int dir = getDirection(meta); + x += footBlockToHeadBlockMap[dir][0]; + z += footBlockToHeadBlockMap[dir][1]; + } + return new ChunkCoordinates(x, y, z); + } + public static boolean isSleepingInPortableBag(EntityPlayer player) { return Wearing.isWearingBackpack(player) && Wearing.getWearingBackpackInv(player).getExtendedProperties().hasKey(Constants.TAG_SLEEPING_IN_BAG); @@ -92,37 +95,27 @@ public static void packPortableSleepingBag(EntityPlayer player) { } } - public static void storeOriginalSpawn(EntityPlayer player, NBTTagCompound tag) { - ChunkCoordinates spawn = player.getBedLocation(player.worldObj.provider.dimensionId); - if (spawn != null) { - NBTTagCompound storedSpawn = new NBTTagCompound(); - storedSpawn.setInteger(TAG_SPAWN_POS_X, spawn.posX); - storedSpawn.setInteger(TAG_SPAWN_POS_Y, spawn.posY); - storedSpawn.setInteger(TAG_SPAWN_POS_Z, spawn.posZ); - tag.setTag(TAG_STORED_SPAWN, storedSpawn); - LogHelper.info( - "Stored spawn data for " + player - .getDisplayName() + ": " + spawn + " dimID: " + player.worldObj.provider.dimensionId); - } else { - LogHelper.warn("Cannot store spawn data for " + player.getDisplayName()); + public static void restoreOriginalSpawn(EntityPlayer player) { + final BackpackProperty props = BackpackProperty.get(player); + + if (props != null) { + final ChunkCoordinates oldSpawn = props.getStoredSpawn(); + if (oldSpawn != null) { + player.setSpawnChunk(oldSpawn, false, props.getStoredSpawnDimension()); + } } } - public static void restoreOriginalSpawn(EntityPlayer player, NBTTagCompound tag) { - if (tag.hasKey(TAG_STORED_SPAWN)) { - NBTTagCompound storedSpawn = tag.getCompoundTag(TAG_STORED_SPAWN); - ChunkCoordinates coords = new ChunkCoordinates( - storedSpawn.getInteger(TAG_SPAWN_POS_X), - storedSpawn.getInteger(TAG_SPAWN_POS_Y), - storedSpawn.getInteger(TAG_SPAWN_POS_Z)); - player.setSpawnChunk(coords, false, player.worldObj.provider.dimensionId); - tag.removeTag(TAG_STORED_SPAWN); - LogHelper.info( - "Restored spawn data for " + player - .getDisplayName() + ": " + coords + " dimID: " + player.worldObj.provider.dimensionId); - } else { - LogHelper.warn("No spawn data to restore for " + player.getDisplayName()); - } + public static boolean shouldRestoreStoredSpawnOnDeath(EntityPlayer player) { + BackpackProperty prop = BackpackProperty.get(player); + if (prop == null) return false; + + ChunkCoordinates sleepingBagSpawn = prop.getSleepingBagSpawn(); + if (sleepingBagSpawn == null) return false; + if (prop.getSleepingBagSpawnDimension() != player.dimension) return false; + + return player.worldObj.getBlock(sleepingBagSpawn.posX, sleepingBagSpawn.posY, sleepingBagSpawn.posZ) + != ModBlocks.blockSleepingBag; } public void onPortableBlockActivated(World world, EntityPlayer player, int cX, int cY, int cZ) { @@ -177,26 +170,36 @@ public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer p setBedOccupied(world, x, y, z, false); } + BackpackProperty props = BackpackProperty.get(player); + ChunkCoordinates previousSpawn = player.getBedLocation(player.dimension); + int previousSpawnDimension = player.dimension; EntityPlayer.EnumStatus enumstatus = player.sleepInBedAt(x, y, z); if (enumstatus == EntityPlayer.EnumStatus.OK) { setBedOccupied(world, x, y, z, true); + ChunkCoordinates sleepingBagSpawn = new ChunkCoordinates(x, y, z); + if (props != null) { + props.setSleepingBagSpawn(sleepingBagSpawn, player.dimension); + if (previousSpawn != null) { + props.setStoredSpawn(previousSpawn, previousSpawnDimension); + } + } // This is so the wake-up event can detect it. It fires before the player wakes up. // and the bed location isn't set until then, normally. - if (isSleepingInPortableBag(player)) { - storeOriginalSpawn(player, Wearing.getWearingBackpackInv(player).getExtendedProperties()); - player.setSpawnChunk(new ChunkCoordinates(x, y, z), true, player.dimension); - } else { - player.setSpawnChunk(new ChunkCoordinates(x, y, z), true, player.dimension); + if (!isSleepingInPortableBag(player)) { LogHelper.info("Looking for a campfire nearby..."); ChunkCoordinates campfire = CoordsUtils .findBlock3D(world, x, y, z, ModBlocks.blockCampFire, 8, 2); if (campfire != null) { LogHelper.info("Campfire Found, saving coordinates. " + campfire); BackpackProperty.get(player).setCampFire(campfire); + } else { + LogHelper.info("No campfire found. Keeping spawnpoint at previous location"); + BackpackProperty.get(player).setCampFire(null); } } + player.setSpawnChunk(sleepingBagSpawn, true, player.dimension); return true; } else { if (enumstatus == EntityPlayer.EnumStatus.NOT_POSSIBLE_NOW) { @@ -299,33 +302,36 @@ public void onBlockDestroyedByExplosion(World world, int x, int y, int z, Explos @Override public void onBlockDestroyedByPlayer(World world, int x, int y, int z, int meta) { - // TODO make it work if player destroyed head block of sleeping bag (so backpack 1 more tile away) - // LogHelper.info("onBlockDestroyedByPlayer() : BlockSleepingBag"); + ChunkCoordinates head = getHeadCoordinates(x, y, z, meta); int direction = getDirection(meta); int tileZ = z; int tileX = x; - switch (meta) { - case 0: - tileZ--; - break; - case 1: - tileX++; - break; - case 2: - tileZ++; - break; - case 3: - tileX--; - break; + if (isBlockHeadOfBed(meta)) { + tileX -= footBlockToHeadBlockMap[direction][0]; + tileZ -= footBlockToHeadBlockMap[direction][1]; + } else { + tileX += footBlockToHeadBlockMap[direction][0]; + tileZ += footBlockToHeadBlockMap[direction][1]; } - // LogHelper.info("onBlockDestroyedByPlayer() Looking for tile entity in x=" +tileX+" y="+y+" z="+tileZ+" while - // breaking the block in x= "+x+" y="+y+" z="+z); if (world.getTileEntity(tileX, y, tileZ) != null && world.getTileEntity(tileX, y, tileZ) instanceof TileAdventureBackpack) { - // LogHelper.info("onBlockDestroyedByPlayer() Found the tile entity in x=" +tileX+" y="+y+" z="+z+" while - // breaking the block in x= "+x+" y="+y+" z="+z+" ...removing."); ((TileAdventureBackpack) world.getTileEntity(tileX, y, tileZ)).setSleepingBagDeployed(false); } + + if (!world.isRemote) { + for (Object object : world.playerEntities) { + EntityPlayer player = (EntityPlayer) object; + BackpackProperty props = BackpackProperty.get(player); + if (props != null && props.getSleepingBagSpawn() != null + && props.getSleepingBagSpawnDimension() == world.provider.dimensionId + && props.getSleepingBagSpawn().posX == head.posX + && props.getSleepingBagSpawn().posY == head.posY + && props.getSleepingBagSpawn().posZ == head.posZ) { + restoreOriginalSpawn(player); + props.clearSleepingBagSpawn(); + } + } + } } @Override diff --git a/src/main/java/com/darkona/adventurebackpack/handlers/PlayerEventHandler.java b/src/main/java/com/darkona/adventurebackpack/handlers/PlayerEventHandler.java index fd86a329..c272dd8c 100644 --- a/src/main/java/com/darkona/adventurebackpack/handlers/PlayerEventHandler.java +++ b/src/main/java/com/darkona/adventurebackpack/handlers/PlayerEventHandler.java @@ -1,6 +1,7 @@ package com.darkona.adventurebackpack.handlers; import java.util.HashSet; +import java.util.Objects; import net.minecraft.entity.EntityCreature; import net.minecraft.entity.SharedMonsterAttributes; @@ -165,6 +166,11 @@ public void playerDies(LivingDeathEvent event) { // point if there's no campfire. } + if (BlockSleepingBag.shouldRestoreStoredSpawnOnDeath(player)) { + BlockSleepingBag.restoreOriginalSpawn(player); + props.clearSleepingBagSpawn(); + } + if (Wearing.isWearingWearable(player)) { if (Wearing.isWearingTheRightBackpack(player, BackpackTypes.CREEPER)) { player.worldObj.createExplosion(player, player.posX, player.posY, player.posZ, 4.0F, false); @@ -172,11 +178,11 @@ public void playerDies(LivingDeathEvent event) { if (player.getEntityWorld().getGameRules().getGameRuleBooleanValue("keepInventory") || PotionAndEnchantUtils.hasStickyItems(player)) { - ((IBackWearableItem) props.getWearable().getItem()) + ((IBackWearableItem) Objects.requireNonNull(props.getWearable().getItem())) .onPlayerDeath(player.worldObj, player, props.getWearable()); - ServerProxy.storePlayerProps(player); } } + ServerProxy.storePlayerProps(player); } } event.setResult(Event.Result.ALLOW); @@ -275,36 +281,46 @@ public void playerWokeUp(PlayerWakeUpEvent event) { ChunkCoordinates bedLocation = player.getBedLocation(player.dimension); if (bedLocation != null && player.worldObj.getBlock(bedLocation.posX, bedLocation.posY, bedLocation.posZ) == ModBlocks.blockSleepingBag) { - // If the player wakes up in one of those super confortable SleepingBags (tm) (Patent Pending) + // If the player wakes up in one of those super comfortable SleepingBags (tm) (Patent Pending) if (BlockSleepingBag.isSleepingInPortableBag(player)) { BlockSleepingBag.packPortableSleepingBag(player); BackpackProperty.get(player).setWakingUpInPortableBag(true); LogHelper.info("Player just woke up in a portable sleeping bag."); } else { - BackpackProperty.get(player).setForceCampFire(true); - LogHelper.info( - "Player just woke up in a sleeping bag, forcing respawn in the last lighted campfire, if there's any"); + BackpackProperty props = BackpackProperty.get(player); + if (props != null) { + if (props.getCampFire() != null) { + props.setForceCampFire(true); + LogHelper.info( + "Player just woke up in a deployed sleeping bag, forcing respawn near the last lit campfire"); + } else { + LogHelper.info("Player just woke up in a deployed sleeping bag away from any campfire"); + } + } } } else { // If it's a regular bed or whatever - BackpackProperty.get(player).setForceCampFire(false); + BackpackProperty props = BackpackProperty.get(player); + props.setForceCampFire(false); + props.clearSleepingBagSpawn(); } } @SubscribeEvent public void tickPlayer(TickEvent.PlayerTickEvent event) { EntityPlayer player = event.player; - if (player != null && !player.isDead && Wearing.isWearingWearable(player)) { - if (event.phase == TickEvent.Phase.START) { - BackpackProperty.get(player).executeWearableUpdateProtocol(); - } - if (event.phase == TickEvent.Phase.END) { - if (!player.worldObj.isRemote) { - if (BackpackProperty.get(player).isWakingUpInPortableBag() && Wearing.isWearingBackpack(player)) { - BlockSleepingBag.restoreOriginalSpawn( - player, - Wearing.getWearingBackpackInv(player).getExtendedProperties()); - BackpackProperty.get(player).setWakingUpInPortableBag(false); + if (player != null && !player.isDead) { + if (Wearing.isWearingWearable(player)) { + if (event.phase == TickEvent.Phase.START) { + BackpackProperty.get(player).executeWearableUpdateProtocol(); + } + if (event.phase == TickEvent.Phase.END) { + if (!player.worldObj.isRemote) { + if (BackpackProperty.get(player).isWakingUpInPortableBag() + && Wearing.isWearingBackpack(player)) { + BlockSleepingBag.restoreOriginalSpawn(player); + BackpackProperty.get(player).setWakingUpInPortableBag(false); + } } } } diff --git a/src/main/java/com/darkona/adventurebackpack/playerProperties/BackpackProperty.java b/src/main/java/com/darkona/adventurebackpack/playerProperties/BackpackProperty.java index 16d1734d..31218a50 100644 --- a/src/main/java/com/darkona/adventurebackpack/playerProperties/BackpackProperty.java +++ b/src/main/java/com/darkona/adventurebackpack/playerProperties/BackpackProperty.java @@ -16,9 +16,15 @@ public class BackpackProperty implements IExtendedEntityProperties { private static final String PROPERTY_NAME = "abp.property"; + private static final String TAG_STORED_SPAWN = "storedSpawn"; + private static final String TAG_SLEEPING_BAG_SPAWN = "sleepingBagSpawn"; private EntityPlayer player; private ItemStack wearable = null; + private ChunkCoordinates storedSpawn = null; + private int storedSpawnDimension = 0; + private ChunkCoordinates sleepingBagSpawn = null; + private int sleepingBagSpawnDimension = 0; private ChunkCoordinates campFire = null; private boolean forceCampFire = false; private int dimension = 0; @@ -72,6 +78,22 @@ public static BackpackProperty get(EntityPlayer player) { @Override public void saveNBTData(NBTTagCompound compound) { if (wearable != null) compound.setTag("wearable", wearable.writeToNBT(new NBTTagCompound())); + if (storedSpawn != null) { + NBTTagCompound spawn = new NBTTagCompound(); + spawn.setInteger("posX", storedSpawn.posX); + spawn.setInteger("posY", storedSpawn.posY); + spawn.setInteger("posZ", storedSpawn.posZ); + spawn.setInteger("dim", storedSpawnDimension); + compound.setTag(TAG_STORED_SPAWN, spawn); + } + if (sleepingBagSpawn != null) { + NBTTagCompound spawn = new NBTTagCompound(); + spawn.setInteger("posX", sleepingBagSpawn.posX); + spawn.setInteger("posY", sleepingBagSpawn.posY); + spawn.setInteger("posZ", sleepingBagSpawn.posZ); + spawn.setInteger("dim", sleepingBagSpawnDimension); + compound.setTag(TAG_SLEEPING_BAG_SPAWN, spawn); + } if (campFire != null) { compound.setInteger("campFireX", campFire.posX); compound.setInteger("campFireY", campFire.posY); @@ -87,6 +109,24 @@ public void loadNBTData(NBTTagCompound compound) { setWearable( compound.hasKey("wearable") ? ItemStack.loadItemStackFromNBT(compound.getCompoundTag("wearable")) : null); + if (compound.hasKey(TAG_STORED_SPAWN)) { + NBTTagCompound spawn = compound.getCompoundTag(TAG_STORED_SPAWN); + setStoredSpawn( + new ChunkCoordinates( + spawn.getInteger("posX"), + spawn.getInteger("posY"), + spawn.getInteger("posZ")), + spawn.getInteger("dim")); + } + if (compound.hasKey(TAG_SLEEPING_BAG_SPAWN)) { + NBTTagCompound spawn = compound.getCompoundTag(TAG_SLEEPING_BAG_SPAWN); + setSleepingBagSpawn( + new ChunkCoordinates( + spawn.getInteger("posX"), + spawn.getInteger("posY"), + spawn.getInteger("posZ")), + spawn.getInteger("dim")); + } setCampFire( new ChunkCoordinates( compound.getInteger("campFireX"), @@ -110,6 +150,41 @@ public ItemStack getWearable() { return wearable; } + public void setStoredSpawn(ChunkCoordinates coords) { + setStoredSpawn(coords, player.worldObj.provider.dimensionId); + } + + public void setStoredSpawn(ChunkCoordinates coords, int dim) { + storedSpawn = coords; + storedSpawnDimension = dim; + } + + public ChunkCoordinates getStoredSpawn() { + return storedSpawn; + } + + public int getStoredSpawnDimension() { + return storedSpawnDimension; + } + + public void setSleepingBagSpawn(ChunkCoordinates coords, int dim) { + sleepingBagSpawn = coords; + sleepingBagSpawnDimension = dim; + } + + public ChunkCoordinates getSleepingBagSpawn() { + return sleepingBagSpawn; + } + + public int getSleepingBagSpawnDimension() { + return sleepingBagSpawnDimension; + } + + public void clearSleepingBagSpawn() { + sleepingBagSpawn = null; + sleepingBagSpawnDimension = 0; + } + public void setCampFire(ChunkCoordinates cf) { campFire = cf; }