Fix syncing of everything

This commit is contained in:
Electroblob77
2020-04-12 18:35:30 +01:00
parent 6254020024
commit c622158818
9 changed files with 124 additions and 36 deletions
@@ -1,5 +1,7 @@
package electroblob.wizardry;
import electroblob.wizardry.block.BlockBookshelf;
import electroblob.wizardry.inventory.ContainerArcaneWorkbench;
import electroblob.wizardry.item.ItemSpectralBow;
import electroblob.wizardry.packet.*;
import electroblob.wizardry.registry.WizardryItems;
@@ -261,4 +263,17 @@ public class CommonProxy {
public Set<String> getSpellHUDSkins(){
return null;
}
/** Notifies nearby players of a bookshelf change, causing any lectern or arcane workbench GUI (client-side) or
* container (both sides) to refresh its linked bookshelves (does not send packets). */
public void notifyBookshelfChange(World world, BlockPos pos){
for(EntityPlayer player : world.playerEntities){
if(player.getDistanceSq(pos) < BlockBookshelf.PLAYER_NOTIFY_RANGE * BlockBookshelf.PLAYER_NOTIFY_RANGE){
if(player.openContainer instanceof ContainerArcaneWorkbench){
((ContainerArcaneWorkbench)player.openContainer).refreshBookshelfSlots();
}
}
}
}
}
@@ -12,6 +12,7 @@ import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.BlockStateContainer;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
@@ -19,19 +20,30 @@ import net.minecraft.inventory.InventoryHelper;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.IWorldEventListener;
import net.minecraft.world.World;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.Properties;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.lang3.ArrayUtils;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
@Mod.EventBusSubscriber
public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvider {
/** When a bookshelf block (of any kind specified in the config) is added or removed, players within this range will
* be notified of the change. */
public static final double PLAYER_NOTIFY_RANGE = 32;
public static final int SLOT_COUNT = 12;
public static final UnlistedPropertyBool[] BOOKS = new UnlistedPropertyBool[SLOT_COUNT];
@@ -65,6 +77,11 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid
return this.getDefaultState().withProperty(FACING, placer.getHorizontalFacing().getOpposite());
}
@Override
public void onBlockAdded(World worldIn, BlockPos pos, IBlockState state){
super.onBlockAdded(worldIn, pos, state);
}
@Override
public void breakBlock(World world, BlockPos pos, IBlockState block){
@@ -172,4 +189,49 @@ public class BlockBookshelf extends BlockHorizontal implements ITileEntityProvid
}
@SubscribeEvent
public static void onWorldLoadEvent(WorldEvent.Load event){
event.getWorld().addEventListener(Listener.instance);
}
@SubscribeEvent
public static void onWorldUnloadEvent(WorldEvent.Unload event){
event.getWorld().removeEventListener(Listener.instance);
}
public static class Listener implements IWorldEventListener {
public static final Listener instance = new Listener();
private Listener(){}
@Override
public void notifyBlockUpdate(World world, BlockPos pos, IBlockState oldState, IBlockState newState, int flags){
if(oldState == newState) return; // Probably won't happen but just in case
if(Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, oldState) // Bookshelf removed
|| Settings.containsMetaBlock(Wizardry.settings.bookshelfBlocks, newState)){ // Bookshelf placed
// It is also possible (with commands) for a bookshelf to be replaced with another bookshelf, in which
// case this should still just be called once
Wizardry.proxy.notifyBookshelfChange(world, pos);
}
}
// Dummy implementations
@Override public void notifyLightSet(BlockPos pos){}
@Override public void markBlockRangeForRenderUpdate(int x1, int y1, int z1, int x2, int y2, int z2){}
@Override public void playSoundToAllNearExcept(@Nullable EntityPlayer player, SoundEvent soundIn, SoundCategory category, double x, double y, double z, float volume, float pitch){}
@Override public void playRecord(SoundEvent soundIn, BlockPos pos){}
@Override public void spawnParticle(int particleID, boolean ignoreRange, double xCoord, double yCoord, double zCoord, double xSpeed, double ySpeed, double zSpeed, int... parameters){}
@Override public void spawnParticle(int id, boolean ignoreRange, boolean minimiseParticleLevel, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed, int... parameters){}
@Override public void onEntityAdded(Entity entityIn){}
@Override public void onEntityRemoved(Entity entityIn){}
@Override public void broadcastSound(int soundID, BlockPos pos, int data){}
@Override public void playEvent(EntityPlayer player, int type, BlockPos blockPosIn, int data){}
@Override public void sendBlockBreakProgress(int breakerId, BlockPos pos, int progress){}
}
}
@@ -2,9 +2,11 @@ package electroblob.wizardry.client;
import electroblob.wizardry.CommonProxy;
import electroblob.wizardry.Wizardry;
import electroblob.wizardry.block.BlockBookshelf;
import electroblob.wizardry.client.audio.MovingSoundEntity;
import electroblob.wizardry.client.audio.SoundLoop;
import electroblob.wizardry.client.audio.SoundLoopSpell;
import electroblob.wizardry.client.gui.GuiLectern;
import electroblob.wizardry.client.gui.GuiSpellDisplay;
import electroblob.wizardry.client.gui.config.NamedBooleanEntry;
import electroblob.wizardry.client.gui.config.SpellHUDSkinChooserEntry;
@@ -202,6 +204,20 @@ public class ClientProxy extends CommonProxy {
return GuiSpellDisplay.getSkinKeys();
}
@Override
public void notifyBookshelfChange(World world, BlockPos pos){
super.notifyBookshelfChange(world, pos);
EntityPlayer player = Minecraft.getMinecraft().player;
if(player.getDistanceSq(pos) < BlockBookshelf.PLAYER_NOTIFY_RANGE * BlockBookshelf.PLAYER_NOTIFY_RANGE){
if(Minecraft.getMinecraft().currentScreen instanceof GuiLectern){
((GuiLectern)Minecraft.getMinecraft().currentScreen).refreshAvailableSpells();
}
}
}
// SECTION Items
// ===============================================================================================================
@@ -127,8 +127,6 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
super.initGui();
updateAvailableSpells();
final int left = this.width / 2 - this.xSize / 2;
final int top = this.height / 2 - this.ySize / 2;
@@ -181,8 +179,7 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
this.searchField.setCanLoseFocus(false);
this.searchField.setFocused(true);
updateMatchingSpells();
updateButtonVisiblity();
refreshAvailableSpells(); // Must be done last
}
@@ -383,9 +380,9 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
.collect(Collectors.toList());
}
// TODO: Call this when a bookshelf is added or removed
// TODO: Config option to always display all spells when in creative
private void updateAvailableSpells(){
/** Called on initialisation and whenever a bookshelf is added or removed, to update the list of spells. */
public void refreshAvailableSpells(){
availableSpells.clear();
@@ -405,6 +402,9 @@ public class GuiLectern extends GuiSpellInfo implements ISpellSortable {
if(!availableSpells.contains(currentSpell)) currentSpell = Spells.none; // TODO: Do we want this?
updateMatchingSpells();
updateButtonVisiblity();
}
private class GuiButtonLocateBook extends GuiButton {
@@ -36,7 +36,9 @@ public class BakedModelBookshelf implements IBakedModel {
IExtendedBlockState extendedState = (IExtendedBlockState)state;
for(int i = 0; i<BlockBookshelf.SLOT_COUNT; i++){
if(extendedState.getValue(BlockBookshelf.BOOKS[i])) quads.addAll(books[i].getQuads(state, side, rand));
Boolean value = extendedState.getValue(BlockBookshelf.BOOKS[i]);
if(value == null) return fallback.getQuads(null, side, rand);
if(value) quads.addAll(books[i].getQuads(state, side, rand));
}
return quads;
@@ -212,11 +212,6 @@ public class ContainerArcaneWorkbench extends Container implements ISpellSortabl
}
}
}
// FIXME: It only seems to be syncing correctly when a stack is put into the slot, not taken out.
// This is because markDirty isn't called in the tileentity, I think.
// You can simulate this using hoppers!
this.tileentity.sync();
}
// FIXME: Shift-clicking a stack of special upgrades when in the arcane workbench causes the whole stack to be
@@ -516,9 +511,8 @@ public class ContainerArcaneWorkbench extends Container implements ISpellSortabl
// N.B. If we drop the requirement of it working with any container it could potentially be a lot easier since
// we then always have control over the bookshelf classes
// TODO: Call this when a bookshelf is added or removed
/** Called on initialisation, and whenever a bookshelf is added or removed. */
private void refreshBookshelfSlots(){
/** Called on initialisation and whenever a bookshelf is added or removed, to update the virtual slot list. */
public void refreshBookshelfSlots(){
this.inventorySlots.removeAll(bookshelfSlots);
bookshelfSlots.clear();
@@ -48,7 +48,7 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory,
/** Called to manually sync the tile entity with clients. */
public void sync(){
this.world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
this.world.markAndNotifyBlock(pos, null, world.getBlockState(pos), world.getBlockState(pos), 3);
}
@Override
@@ -113,8 +113,11 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory,
@Override
public void setInventorySlotContents(int slot, ItemStack stack){
inventory.set(slot, stack);
ItemStack previous = inventory.set(slot, stack);
// Only the central slot affects the in-world rendering, so only sync if that changes
if(slot == ContainerArcaneWorkbench.CENTRE_SLOT && previous.isEmpty() != stack.isEmpty()) this.sync();
if(!stack.isEmpty() && stack.getCount() > getInventoryStackLimit()){
stack.setCount(getInventoryStackLimit());
@@ -199,12 +202,10 @@ public class TileEntityArcaneWorkbench extends TileEntity implements IInventory,
NBTTagList itemList = new NBTTagList();
for(int i = 0; i < getSizeInventory(); i++){
ItemStack stack = getStackInSlot(i);
if(!stack.isEmpty()){
NBTTagCompound tag = new NBTTagCompound();
tag.setByte("Slot", (byte)i);
stack.writeToNBT(tag);
itemList.appendTag(tag);
}
NBTTagCompound tag = new NBTTagCompound();
tag.setByte("Slot", (byte)i);
stack.writeToNBT(tag);
itemList.appendTag(tag);
}
NBTExtras.storeTagSafely(tagCompound, "Inventory", itemList);
@@ -30,7 +30,7 @@ public class TileEntityBookshelf extends TileEntity implements IInventory, ITick
/** Called to manually sync the tile entity with clients. */
public void sync(){
this.world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
this.world.markAndNotifyBlock(pos, null, world.getBlockState(pos), world.getBlockState(pos), 3);
}
@Override
@@ -82,16 +82,15 @@ public class TileEntityBookshelf extends TileEntity implements IInventory, ITick
@Override
public void setInventorySlotContents(int slot, ItemStack stack){
inventory.set(slot, stack);
//ItemStack previous = inventory.set(slot, stack);
ItemStack previous = inventory.set(slot, stack);
//if(previous.isEmpty() != stack.isEmpty()) this.sync();
if(previous.isEmpty() != stack.isEmpty()) this.sync();
if(!stack.isEmpty() && stack.getCount() > getInventoryStackLimit()){
stack.setCount(getInventoryStackLimit());
}
}
@Override
@@ -157,12 +156,10 @@ public class TileEntityBookshelf extends TileEntity implements IInventory, ITick
NBTTagList itemList = new NBTTagList();
for(int i = 0; i < getSizeInventory(); i++){
ItemStack stack = getStackInSlot(i);
if(!stack.isEmpty()){
NBTTagCompound tag = new NBTTagCompound();
tag.setByte("Slot", (byte)i);
stack.writeToNBT(tag);
itemList.appendTag(tag);
}
NBTTagCompound tag = new NBTTagCompound();
tag.setByte("Slot", (byte)i);
stack.writeToNBT(tag);
itemList.appendTag(tag);
}
NBTExtras.storeTagSafely(tagCompound, "Inventory", itemList);
@@ -182,6 +179,7 @@ public class TileEntityBookshelf extends TileEntity implements IInventory, ITick
@Override
public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt){
readFromNBT(pkt.getNbtCompound());
Wizardry.proxy.notifyBookshelfChange(world, pos);
}
// What are all these for?
@@ -64,7 +64,7 @@ public class TileEntityLectern extends TileEntity implements ITickable {
/** Called to manually sync the tile entity with clients. */
public void sync(){
this.world.notifyBlockUpdate(pos, world.getBlockState(pos), world.getBlockState(pos), 3);
this.world.markAndNotifyBlock(pos, null, world.getBlockState(pos), world.getBlockState(pos), 3);
}
@Override