Jump to content

Bektor

Forge Modder
  • Posts

    852
  • Joined

  • Last visited

Posts posted by Bektor

  1. 2 minutes ago, Draco18s said:

    GameRegistry.register is private in 1.12, so I don't know how you're using it. You should be using the Registry events.

     

    I'm not using GameRegistry.register. The code is from 1.10.2 and my goal is to have a system which does something similiar in 1.12 using Registry events. I know how to register blocks and

    items with the registry events, but I don't know how to do it in a flexible way like my old code allowed it.

     

    4 minutes ago, Draco18s said:

    If you want to have a one-line registration and handle everything all at once regardless of how you want to register the block, check out my EasyRegistry classes:

    https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/hardlib/EasyRegistry.java

    https://github.com/Draco18s/ReasonableRealism/blob/1.12.1/src/main/java/com/draco18s/hardlib/client/ClientEasyRegistry.java

     

    note that the classes are both proxy and event handler.

    Ok,I'm looking into it. ;) 

  2. Hi,

     

    I've got the following code I've used so far for handling all varius aspects of registering my blocks and the models for its. This code is for blocks only, but I've got some similiar code for items, too.

     

    My problem is now, I'm currently porting some things from my mod over to 1.12.1 and 1.11.2 with using the new RegistryEvents, but I don't want to lose  the flexibility of the system I've got below.

    Note: This system was also used in my old mod for orginizing stuff. This means I've used it in my old mod also to register everything with sub-folders. For example I've got those paths when a block had multiply variants and still want to have it as an

    optional part in my 1.12 code with the RegistryEvents.

    Quote

    assets.primevalforest.models.item.stoneBrick

    assets.primevalforest.textures.blocks.rocks

    	/**
    	 * Provides the functionality of automatically registering the block and
    	 * setting the registry name and unlocalized name. It also registered
    	 * the block JSON renderer's and the item block with it's JSON renderer's.
    	 * 
    	 * @param block The block to register
    	 * @param name The unique name of the block
    	 * @param itemFactory  A function that creates the ItemBlock instance, or null if no ItemBlock should be created
    	 * @param withMeta Should the meta data of the block also be registered?
    	 * @return The block
    	 */
    	public static Block register(Block block, String name, @Nullable Function<Block, ItemBlock> itemFactory, boolean withMeta) {
    		block.setUnlocalizedName(Constants.MOD_ID.toLowerCase() + "." + name);
    		block.setRegistryName(name);
    		GameRegistry.register(block);
    		
    		if(itemFactory != null) {
    			final ItemBlock itemBlock = itemFactory.apply(block);
    			GameRegistry.register(itemBlock.setRegistryName(block.getRegistryName()));
    			
    			if(block instanceof IItemOreDict)
    				((IItemOreDict)block).initOreDict();
    			
    			if(itemBlock instanceof IItemOreDict)
    				((IItemOreDict)itemBlock).initOreDict();
    			
    			if(FMLCommonHandler.instance().getEffectiveSide().isClient())
    				BlockRegistry.registerRenderer(block, withMeta);
    		}
    		
    		return block;
    	}
    	
    	/**
    	 * Provides the functionality of automatically registering the block 
    	 * JSON renderer's and the item block with it's JSON renderer's.
    	 * 
    	 * @param block The block to register
    	 * @param withMeta Should the meta data of the block also be registered?
    	 * @return If the registration of the JSON renderer was successful.
    	 */
    	@SideOnly(Side.CLIENT)
    	private static boolean registerRenderer(Block block, boolean withMeta) {
    		Iterator<IBlockState> it = block.getBlockState().getValidStates().iterator();
    		boolean flag = true;
    		
    		while(it.hasNext()) {
    			IBlockState state = it.next();
    			
    			if(state == null) {
    				JustAnotherEnergy.getLogger().error("Skipping block rendering registration for {}", state);
    				flag = false;
    				break;
    			}
    			
    			int meta = block.getMetaFromState(state);
    			RenderUtil.renderBlock(block, withMeta ? meta : 0);
    		}
    		return flag;
    	}
    	
    		/**
    	 * Provides the functionality of automatically registering the block and
    	 * setting the registry name and unlocalized name. It also registered
    	 * the block JSON renderer's and the item block with it's JSON renderer's.
    	 * <p>
    	 * This method tells Minecraft that the model json's can be found in a sub-folder.
    	 * 
    	 * @param block The block to register
    	 * @param name The unique name of the block
    	 * @param itemFactory  A function that creates the ItemBlock instance, or null if no ItemBlock should be created
    	 * @param withMeta Should the meta data of the block also be registered?
    	 * @param variants The different variants in which block comes
    	 * @return The block
    	 */
    	public static <T extends IType> Block register(Block block, String name, @Nullable Function<Block, ItemBlock> itemFactory, boolean withMeta, @Nullable T[] variants) {
    		block.setUnlocalizedName(Constants.MOD_ID.toLowerCase() + "." + name);
    		block.setRegistryName(name);
    		GameRegistry.register(block);
    		
    		if(itemFactory != null) {
    			final ItemBlock itemBlock = itemFactory.apply(block);
    			GameRegistry.register(itemBlock.setRegistryName(block.getRegistryName()));
    			
    			if(FMLCommonHandler.instance().getEffectiveSide().isClient()) {
    				Iterator<IBlockState> it = block.getBlockState().getValidStates().iterator();
    				
    				while(it.hasNext()) {
    					IBlockState state = it.next();
    					
    					if(state == null) {
    						JustAnotherEnergy.getLogger().error("Skipping block rendering registration for {}", state);
    						break;
    					}
    					
    					for(T variant : variants) {
    						RenderUtil.renderBlock(BlockRegistry.getResourcePath(name), block, variant.getID(), variant.getName());
    					}
    				}
    			}
    		}
    		
    		return block;
    	}

     

    Thx in advance.

    Bektor

  3. Hi,

     

    I am wondering whether it is possible to stop the ore generation of all ores registered using the OreDic,

    for example if two hundred mods provide their own copper ore, I want my mod to just replace all those

    copper ores in world generation with my copper ore.

     

    This means the goal is to have a universal for example copper ore for world generation instead of having 

    each mod generate their own copper ore or having to look into every config file if the mod XX provides an

    option to disable the ore gen.

     

    I am also wondering if it is possible with using the ore dictionary to replace the smelting recipes to output

    my for example copper ingot.

     

    In Short:

    • How to stop Mod Ore Generation for for example all copper ores which are registered using OreDic?
    • How to replace the smelting output for all with OreDic registered for example copper ores to be my copper ingot?

    Why do I want to do this?

    • To only have one ore generated of each ore type (for example only one copper ore gets generated etc.)

     

    Thx in advance.

    Bektor

  4. Just now, Draco18s said:

    I didn't have a good way of mapping multiple chunks to one ticket.

    Well, I've got a method which could do it if I would finally figure out how to get a circle shape of 9 chunks in a damn for-loop. xD

    (and if I would know how to fix the problem)

    Might be you want to take a look at my method if you at some point want to store multiply chunks to one ticket.

  5. On 8/25/2017 at 0:05 AM, Draco18s said:

    My code uses a separate ticket for each chunk. I am not 100% sure at this point that that is required, but I know that my code can take advantage of that.

     

    This code is in my main class because the code is not sided. Both the client and server need to know about the chunks being loaded.

     

    I use a list (actually a HashMap) because I need to keep track of all of the tickets and I need to know if the ticket for a given chunk is active or not (if it's active, increment the number of active "references" to that ticket).

    Ah, ok that makes it clear. I don't think it is required to create a seperate ticket for reach chunk. I saw some chunkloader mods to load up to 27 chunks with one ticket. If I recall correctly 27 is also the default limit.

     

    I've just updated the code in the main post as I changed some lines after looking at your code, thought the problem still remains.

    (I couldn't yet figure out what causes the problem  :(

    Thought it is interesting that when enough energy is there for one tick until it has to refill for one or two ticks, the problem also occurs.

     

    Hm, on my side the code is currently not called on the client side (as it relies on energy logic stuff which is server side only). See the flag boolean with the consume method. ;) I also do not call forceChunk multiply times for one ticket (which is recommended) as my current code does not support this kind of stuff.

  6. Hi,

     

    I'm wondering if the method onNeighborChange has something like worldIn.isRemote.

    I know that in neighborChanged this statement can be used, but in onNeighborChange it can't.

     

    And I would like to stay with onNeighborChange as it is called for when a tile entity is changed (created, broken) and

    that's really the only case when my code should be executed to get the changed neighbour tileentity directly and add

    it to a list (or remove it if the tile entity is null, thus has been broken).

     

    Thx in advance.

    Bektor

  7. 1 hour ago, Draco18s said:

    I am wondering why you store your ticket in the main class and why you got a list?

    And what exactly does this code? I mean, I can see that it is there to request a ticket and force a chunk to load or unload, but for what is the logic around there?

    Note: I just implemented my logic by looking into what others did and reading the doc for ForgeChunkManager, like the 5 steps described there. So I know not really much about this hole topic of chunk loading.

  8. Hi,

     

    I've created a basic ChunkLoader and would like to get some feedback on the code.

    (The code should be optimized for performance using Java 8).

     

    I've also got the following problem:

    Quote

    Reloading Chunk Loader at BlockPos{x=2169, y=56, z=-554} because XXXX-XXXX-XXXX-XXXX placed or interacted with it.

    The mod XXX attempted to force load a chunk with an invalid ticket. This is not permitted.

    The error occurs in the setTicket method of the TileEntity.

    It should be noted that I haven't figured out which chunks should be loaded except for the chunk the chunk loader is in (see ChunkLoaderManager), so if anyone knows how to achieve this, let me know. ;) 

     

    BlockChunkLoader:

    public class BlockChunkLoader extends Block implements ITileEntityProvider {
        
        public static PropertyEnum<ChunkLoaderTypes> META_PROPERTY = PropertyEnum.create("loader", ChunkLoaderTypes.class);
        
        public BlockChunkLoader() {
            super(Material.IRON);
            this.setDefaultState(this.blockState.getBaseState().withProperty(META_PROPERTY, ChunkLoaderTypes.LOAD_01));
        }
        
        @Override
        public void onBlockPlacedBy(World worldIn, BlockPos pos, IBlockState state, EntityLivingBase placer, ItemStack stack) {
            if(worldIn.isRemote)
                return;
            
            TileEntity tile = worldIn.getTileEntity(pos);
            if(tile != null && tile instanceof TileEntityChunkLoader) {
                TileEntityChunkLoader tileCL = (TileEntityChunkLoader) tile;
                
                if(placer instanceof EntityPlayer) {
                    EntityPlayer player = (EntityPlayer) placer;
                    tileCL.setOwnerId(player.getUniqueID());
                    
                    final ForgeChunkManager.Ticket ticket = ForgeChunkManager.requestPlayerTicket(JustAnotherEnergy.getInstance(), tileCL.getOwnerIdString(), worldIn, Type.NORMAL);
                    
                    if(ticket == null) {
                    	// Forge will log errors here, too
                    	JustAnotherEnergy.getLogger().warn("Chunkloading at {} failed. Most likely the limit was reached. {}", pos, ForgeChunkManager.ticketCountAvailableFor(player.getName()));
                    	return;
                    }
                    
                    final NBTTagCompound modData = ticket.getModData();
                    modData.setTag("blockPosition", NBTUtil.createPosTag(pos));
                    
                    if(this.getMetaFromState(state) == ChunkLoaderTypes.LOAD_01.getID())
                        modData.setInteger("size", 1);
                    else if(this.getMetaFromState(state) == ChunkLoaderTypes.LOAD_09.getID())
                    	modData.setInteger("size", 9);
                    else if(this.getMetaFromState(state) == ChunkLoaderTypes.LOAD_25.getID())
                    	modData.setInteger("size", 25);
                    
                    tileCL.setTicket(ticket);
                    //tileCL.setDefaultTicket(ticket);
                }
            }
        }
        
        @Override
        public void breakBlock(World worldIn, BlockPos pos, IBlockState state) {
            TileEntity tile = worldIn.getTileEntity(pos);
            if(tile != null && tile instanceof TileEntityChunkLoader) {
                TileEntityChunkLoader tileCL = (TileEntityChunkLoader) tile;
                ForgeChunkManager.releaseTicket(tileCL.getTicket());
            }
            
            super.breakBlock(worldIn, pos, state);
        }
        
        @Override
        public TileEntity createNewTileEntity(World worldIn, int meta) {
            switch(meta) {
                case 0: return new TileEntityChunkLoader(500, 500); 
                case 1: return new TileEntityChunkLoader(4500, 900);
                case 2: return new TileEntityChunkLoader(125000, 25000);
                default: return new TileEntityChunkLoader(500, 100);   
            }
        }
        
        @Override
        public void getSubBlocks(Item itemIn, CreativeTabs tab, List<ItemStack> list) {
            for(final ChunkLoaderTypes type : ChunkLoaderTypes.values())
                list.add(new ItemStack(this, 1, type.getID()));
        }
        
        @Override
        public int damageDropped(IBlockState state) {
            return this.getMetaFromState(state);
        }
        
        @Override
        protected BlockStateContainer createBlockState() {
            return new BlockStateContainer(this, META_PROPERTY);
        }
        
        @Override
        public int getMetaFromState(IBlockState state) {
            return state.getValue(META_PROPERTY).getID();
        }
        
        @Override
        public IBlockState getStateFromMeta(int meta) {
            return this.getDefaultState().withProperty(META_PROPERTY, ChunkLoaderTypes.byMetadata(meta));
        }
    }

     

    TileEntityChunkLoader

    public class TileEntityChunkLoader extends TileEntityEnergy {
        
        @Nullable
        private UUID ownerId = null;
        private static final String UUID_TAG = "UUID";
        
        @Nullable
        private ForgeChunkManager.Ticket ticket = null;
        
        /*
         *  ticket used as a default to stop conflicts with changing the actual ticket
         *  implemented to allow the block to not call ChunkLoaderManager.startChunkLoading!
         */
        @Nullable
        private ForgeChunkManager.Ticket dfTicket = null;
        
        private boolean wasActive = false;
        
        public TileEntityChunkLoader() {
        	// this has to be here in order for correct saving and loading of NBT data
    	}
        
        public TileEntityChunkLoader(int capacity, int maxTransfer) {
            super(capacity, maxTransfer, false);
            
            this.getEnergyManager().setTransferMode(EnergyTransfer.CONSUMER);
        }
        
        @Override
        public void update() {
            super.update();
            
            if(!this.hasWorld() || this.getWorld().isRemote || this.ticket == null)
                return;
            
            boolean flag = false;
            flag = EnergyUtils.consumeEnergy(this, 100);
            
            if(flag) {
                if(this.wasActive)
                    ChunkLoaderManager.startChunkLoading(this.getWorld(), this.ticket);
                    //ChunkLoaderManager.startChunkLoading(this.getWorld(), this.dfTicket);
                
                this.getWorld().notifyBlockUpdate(this.getPos(), this.getWorld().getBlockState(this.getPos()), this.getWorld().getBlockState(this.getPos()), 3);
                this.markDirty();
            } else if(this.ticket != null && !flag && !this.wasActive)
                ChunkLoaderManager.stopChunkLoading(this.getWorld(), this.ticket);
            
            if(this.wasActive != flag)
                this.wasActive = flag;
        }
        
        public void setDefaultTicket(@Nonnull Ticket ticket) {
            this.dfTicket = ticket;
        }
        
        public void setTicket(@Nonnull Ticket ticket) {
        	if(this.ticket != null)
        		ForgeChunkManager.releaseTicket(this.ticket);
        	
        	this.ticket = ticket;
        	this.getWorld().addBlockEvent(this.getPos(), this.getBlockType(), 1, 1);
        	JustAnotherEnergy.getLogger().info("Reloading Chunk Loader at {} because {} placed or interacted with it.", this.getPos(), this.ticket.getPlayerName());
        }
        
        public Ticket getTicket() {
        	return this.ticket;
        }
        
        @Override
        public SPacketUpdateTileEntity getUpdatePacket() {
            return new SPacketUpdateTileEntity(this.getPos(), 3, this.getUpdateTag());
        }
        
        @Override
        public NBTTagCompound getUpdateTag() {
            return this.writeToNBT(new NBTTagCompound());
        }
        
        @Override
        public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
            super.onDataPacket(net, pkt);
            this.handleUpdateTag(pkt.getNbtCompound());
        }
        
        @Override
        public void readFromNBT(NBTTagCompound compound) {
        	if(compound.hasKey(TileEntityChunkLoader.UUID_TAG))
        		this.ownerId = compound.getUniqueId(TileEntityChunkLoader.UUID_TAG);
            
            super.readFromNBT(compound);
        }
        
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
        	if(this.ownerId != null)
        		compound.setUniqueId(TileEntityChunkLoader.UUID_TAG, this.ownerId);
            
            return super.writeToNBT(compound);
        }
        
        public void setOwnerId(UUID ownerId) {
            this.ownerId = ownerId;
        }
        
        public String getOwnerIdString() {
        	return this.ownerId.toString();
        }
    }

    ChunkManagerCallback

    public class ChunkManagerCallback implements PlayerOrderedLoadingCallback {
    	
    	@Override
    	public void ticketsLoaded(List<Ticket> tickets, World world) {
    		for(Ticket ticket : tickets) {
    			final NBTTagCompound modData = ticket.getModData();
    			if(!modData.hasKey("blockPosition") || !modData.hasKey("size"))
    				continue;
    			
    			ChunkLoaderManager.startChunkLoading(world, ticket);
    		}
    	}
    	
    	@Override
    	public ListMultimap<String, Ticket> playerTicketsLoaded(ListMultimap<String, Ticket> tickets, World world) {
    		final ListMultimap<String, Ticket> copyTickets = ArrayListMultimap.create();
    		
    		for(String player : tickets.keySet()) {
    			for(Ticket ticket : tickets.values()) {
    				final NBTTagCompound modData = ticket.getModData();
    				if(modData.hasKey("blockPosition") && modData.hasKey("size"))
    					copyTickets.put(player, ticket);
    			}
    		}
    		
    		return copyTickets;
    	}
    }

    ChunkLoaderManager

    public class ChunkLoaderManager {
    	
    	public static void startChunkLoading(World world, Ticket ticket) {
    		if(world == null || ticket == null)
    			return;
    		
    		NBTTagCompound modData = ticket.getModData();
    		if(!modData.hasKey("blockPosition") || !modData.hasKey("size"))
    			return;
    		
    		BlockPos pos = NBTUtil.getPosFromTag(modData.getCompoundTag("blockPosition"));
    		TileEntity tile = world.getTileEntity(pos);
    		if(!(tile instanceof TileEntityChunkLoader))
    			return;
    		
    		int size = modData.getInteger("size");
    		
    		if(size == 1)
    			ForgeChunkManager.forceChunk(ticket, new ChunkPos(pos));
    		
    		// TODO: load radius, eg. size 9 = 9 chunks loaded
    		
    		((TileEntityChunkLoader) tile).setTicket(ticket);
    	}
    	
    	public static void stopChunkLoading(World world, Ticket ticket) {
    		if(world == null || ticket == null)
    			return;
    		
    		NBTTagCompound modData = ticket.getModData();
    		if(!modData.hasKey("blockPosition") || !modData.hasKey("size"))
    			return;
    		
    		int size = modData.getInteger("size");
    		BlockPos pos = NBTUtil.getPosFromTag(modData.getCompoundTag("blockPosition"));
    		
    		if(size == 1)
    			ForgeChunkManager.unforceChunk(ticket, new ChunkPos(pos));
    	}
    }

     

    The ChunkManagerCallback is registered after the blocks are registered in the preInit method.

     

    Thx in advance.

    Bektor

  9. 29 minutes ago, V0idWa1k3r said:

    EntityPlayer.getUUID(GameProfile) returns the UUID of the profile if present, otherwise reroutes to EntityPlayer.getOfflineUUID(String).

    EntityPlayer.getOfflineUUID(String) returns a UUID generated from a username provided prefixed with OfflinePlayer.

    Entity::getPersistentID and Entity::getUniqueID both return the same in case of EntityPlayer - and that would be the result of EntityPlayer.getUUID(GameProfile).

    GameProfile::getId returns the UUID of the profile, or null if it is not present(could not connect to Mojang's servers).

     

    So there are really 2 cases:

    1. The player is logged in and in that case return the UUID from Mojang's servers 
    2. The player is not logged in and in that case return a UUID generated based on their name.

    So all I have to do is call either Entity::getPersistentID or Entity::getUniqueID?

    Also, in case of EntityPlayer, those methods return the same, but what would be the difference if it is no player?

  10. Hi,

     

    I'm currently wondering how to get the UUID of the player, as there are several methods which return a UUID,

    like

    player.getGameProfile().getId()
    player.getPersistentID()
    player.getUniqueID()
    player.getUUID(player.getGameProfile())
    player.getOfflineUUID(username)

     

    As there are so many different methods, I am wondering which one I should use to store the owner of a block in the tileentity, so that only this owner can access the block.

    I would also like to know the difference between all those methods and how those methods handle stuff like for example offline mod when you don't have a internet connection.

     

    Thx in advance.

    Bektor

  11. 3 minutes ago, V0idWa1k3r said:

     

     

    You still have the same issue. Upon deserialization your EnergyManager from NBT you set the energy to 0 as the capacity is 0(as you initiate the container field to have 0 capacity in the parameterless constructor). Then after you are done setting the energy to capacity(which is 0) you read the capacity. The deserialization order is mixed.

    Oh yeah, totally forgot the order of the deserialization method. ^^

    Thx. Now it's working fine. :)

  12. 5 hours ago, V0idWa1k3r said:

    You only need to serialize enough data to be able to successfully create an identical object upon deserialization. 

     

    Ok, I just serialized now all values from the EnergyStorage as my EnergyManager is based on EnergyStorage, but the problem still remains.

     

            private final int consume;
        private boolean isActive = false;
        
        @Nullable
        private UUID ownerId = null;
        private static final String UUID_TAG = "UUID";
        
        public TileEntityChunkLoader() {
        	// this has to be here in order for correct saving and loading of NBT data
        	this.consume = 0;
    	}
        
        public TileEntityChunkLoader(int capacity, int maxTransfer) {
            super(capacity, maxTransfer, false);
            
            this.consume = maxTransfer;
            this.getEnergyManager().setTransferMode(EnergyTransfer.CONSUMER);
        }
    
        @Override
        public void update() {
            super.update();
            
            if(!this.hasWorld() || this.getWorld().isRemote)
                return;
            
            if(!this.isActive) { // isActive is currently always false, will change when logic is applied
                this.getWorld().notifyBlockUpdate(this.getPos(), this.getWorld().getBlockState(this.getPos()), this.getWorld().getBlockState(this.getPos()), 3);
                this.markDirty();
            }
        }
    
        @Override
        public SPacketUpdateTileEntity getUpdatePacket() {
            return new SPacketUpdateTileEntity(this.getPos(), 3, this.getUpdateTag());
        }
        
        @Override
        public NBTTagCompound getUpdateTag() {
            return this.writeToNBT(new NBTTagCompound());
        }
        
        @Override
        public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
            super.onDataPacket(net, pkt);
            this.handleUpdateTag(pkt.getNbtCompound());
        }
        
        @Override
        public void readFromNBT(NBTTagCompound compound) {
            //this.ownerId = compound.getUniqueId(TileEntityChunkLoader.UUID_TAG);
            
            super.readFromNBT(compound);
        }
        
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            //compound.setUniqueId(TileEntityChunkLoader.UUID_TAG, this.ownerId); keeps crashing here (NPE)... :(
            
            return super.writeToNBT(compound);
        }

     

    TileEntityEnergy

        public final EnergyManager container;
        
        public TileEntityEnergy() {
        	this.container = new EnergyManager(0, 0);
    	}
        
        public TileEntityEnergy(int capacity, int maxTransfer) {
            this.container = new EnergyManager(capacity, maxTransfer);
        }
        
        public TileEntityEnergy(int capacity, int maxTransfer, boolean shouldExplode) {
            this.shouldExplode = shouldExplode;
            this.container = new EnergyManager(capacity, maxTransfer);
        }
        
        public TileEntityEnergy(int capacity, int maxReceive, int maxExtract) {
            this.container = new EnergyManager(capacity, maxReceive, maxExtract);
        }
        
        public TileEntityEnergy(int capacity, int maxReceive, int maxExtract, boolean shouldExplode) {
            this.shouldExplode = shouldExplode;
            this.container = new EnergyManager(capacity, maxReceive, maxExtract);
        }
    
        @Override
        public void readFromNBT(NBTTagCompound compound) {
            super.readFromNBT(compound);
            this.container.deserializeNBT(compound.getCompoundTag("Energy"));
        }
        
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            compound.setTag("Energy", this.container.serializeNBT());
            return super.writeToNBT(compound);
        }

     

    EnergyManager:

        @Override
        public NBTTagCompound serializeNBT() {
            final NBTTagCompound nbtTagCompound = new NBTTagCompound();
            
            nbtTagCompound.setInteger("energy", this.energy);
            nbtTagCompound.setInteger("capacity", this.capacity);
            nbtTagCompound.setInteger("extract", this.maxExtract);
            nbtTagCompound.setInteger("receive", this.maxReceive);
            
            return nbtTagCompound;
        }
        
        @Override
        public void deserializeNBT(NBTTagCompound nbt) {
            if(nbt.hasKey("energy")) {
                final int tempEnergy = nbt.getInteger("energy");
                
                // prevent modifying stored energy
                if(tempEnergy >= this.capacity)
                    this.energy = this.capacity;
                else if(tempEnergy < this.capacity)
                    this.energy = tempEnergy;
                else this.energy = 0;
            } else if(nbt.hasKey("Energy")) {
            	// TODO: remove
            	// Fallback to support old alpha versions
                final int tempEnergy = nbt.getInteger("Energy");
                
                // prevent modifying stored energy
                if(tempEnergy >= this.capacity)
                    this.energy = this.capacity;
                else if(tempEnergy < this.capacity)
                    this.energy = tempEnergy;
                else this.energy = 0;
            }
            
            if(nbt.hasKey("capacity"))
            	this.capacity = nbt.getInteger("capacity");
            if(nbt.hasKey("extract"))
            	this.maxExtract = nbt.getInteger("extract");
            if(nbt.hasKey("receive"))
            	this.maxReceive = nbt.getInteger("receive");
        }

     

    Note: Thats not all the code of the classes, but instead the most related code to the problem.

  13. 6 hours ago, V0idWa1k3r said:

    Upon investigating your code I notice that you do not have a default(parameterless) constructor for your TE and I am pretty sure that MC invokes the parameterless one when reading TEs from the disk.

    6 hours ago, V0idWa1k3r said:

    exception is thrown thus preventing your TE from deserializing

    I didn't noticed any exceptions thrown on saving the world thus far, thought I will check it later on.

     

    EDIT: Ok. There are exceptions on loading the game. Thought adding an empty constructor won't fix the problem. No exceptions any more, but the energy value resets to 0.

    Am I also required to save all fields of the EnergyManager to NBT data? ( capacity, maxReceive, maxExtract, shouldExplode etc.)

    I mean, I've already got the fields set in the Block class which calls the constructor with parameters.

  14. Hi,

     

    I've got a few problems with saving NBT data:

     

    1. How can I write and save NBT data when the corresponding value is null?
    2. I've got a machine which should store the energy it has, but on world reload the containing value resets itself to 0.

     

    Corresponding code to 1:

    Note that the value facing might be null.

       private HashMap<BlockPos, EnumFacing> connected = new HashMap<>();
    
        @Override
        public void readFromNBT(NBTTagCompound compound) {
            super.readFromNBT(compound);
        	if(compound.hasKey("connection")) {
                NBTTagList list = compound.getTagList("connection", Constants.NBT.TAG_COMPOUND);
                for(int i = 0; i <= list.tagCount(); i++) {
                    NBTTagCompound com = list.getCompoundTagAt(i);
                    if(com.hasKey("posX") && com.hasKey("posY") && com.hasKey("posZ")
                            && com.hasKey("facing")) {
                        
                        this.connected.put(
                                new BlockPos(
                                        com.getInteger("posX"),
                                        com.getInteger("posY"),
                                        com.getInteger("posZ")), 
                                EnumFacing.byName(com.getString("facing"))); // can be null!!!!
                    }
                }
            }
        }
        
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
        	NBTTagList list = new NBTTagList();
            this.connected.forEach((pos, side) -> {
                NBTTagCompound com = new NBTTagCompound();
                com.setInteger("posX", pos.getX());
                com.setInteger("posY", pos.getY());
                com.setInteger("posZ", pos.getZ());
                com.setString("facing", side.getName()); // can be null!!!
                list.appendTag(com);
            });
            compound.setTag("connection", list);
            
            return super.writeToNBT(compound);
        }

     

     

    The second problem with NBT data:

        @Override
        public void readFromNBT(NBTTagCompound compound) {
            this.ownerId = compound.getUniqueId(TileEntityChunkLoader.UUID_TAG);
            
            super.readFromNBT(compound);
        }
        
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            compound.setUniqueId(TileEntityChunkLoader.UUID_TAG, this.ownerId);
            
            return super.writeToNBT(compound);
        }

    And the corresponding base class from which the read and write methods are overridden:

        public final EnergyManager container;
    
        @Override
        public void readFromNBT(NBTTagCompound compound) {
            super.readFromNBT(compound);
            this.container.deserializeNBT(compound.getCompoundTag("Energy"));
        }
        
        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound compound) {
            compound.setTag("Energy", this.container.serializeNBT());
            return super.writeToNBT(compound);
        }
    Spoiler

    Full code for the second NBT problem:

    machine (java file) 

    TileEntityEnergy.java (base class)

     

    Thx in advance.

    Bektor

  15. 4 hours ago, Rikka0_0 said:

    I guess your energy system simulation logic is server-only

    Yeah, it is mostly server-side only. Thought in onNeighborChange is no check if it is called on server or client side and it works fine there (worldIn.isRemote isn't available there).

    4 hours ago, Rikka0_0 said:

    From what I know, getTileEntity attempts to create an TileEntity if there's no existing one at the given location

    I don't think that is how getTileEntity works as getTileEntity is @Nullable, but I never looked that deep into Minecraft src code.

     

    4 hours ago, Rikka0_0 said:

    Your code looks like updating the appearance of blocks,

    It's not updating the appearance of blocks. It's just adding stuff to a list. The first list, connected, is for all cables which are connected to the transfer tiles and the dc (direct_connect) list is for all machines which are directly connected to the transfer tile.

    I'm actually checking if on side XX is a tile entity. When there is a tile entity, does it have the correct capability facing towards us?

    I'm also making sure it isn't another transfer tile or a energy producer as the dc list is only for sending energy to machines.

    The tiles who are in the dc list also aren't allowed to exist in the connected list.

    So nothing with block appearance. I might also be able to have one list for both cases, but as these cases have a priority, so a machine gets energy before all other transfer tiles and as the search mechanics for both lists are different, I rather have it split up into two different lists.

     

     

  16. 7 hours ago, Rikka0_0 said:

    I saw your blocks have TileEntity. I guess you should replace onBlockAdded() in Block classes with onLoad() in corresponding TileEntity class. The onLoad() event will be fired when ever the TileEntity is being initialize, on both server and client side. Placing block, chunk loading can both trigger onLoad()

    Hm... interesting.. now I'm getting an StackOverflowError:

    Spoiler
    Quote

    [00:04:25] [Server thread/ERROR]: Encountered an unexpected exception
    java.lang.StackOverflowError
        at java.util.zip.Inflater.<init>(Unknown Source) ~[?:1.8.0_144]
        at java.util.zip.Inflater.<init>(Unknown Source) ~[?:1.8.0_144]
        at java.util.zip.InflaterInputStream.<init>(Unknown Source) ~[?:1.8.0_144]
        at net.minecraft.world.chunk.storage.RegionFile.getChunkDataInputStream(RegionFile.java:186) ~[RegionFile.class:?]
        at net.minecraft.world.chunk.storage.RegionFileCache.getChunkInputStream(RegionFileCache.java:72) ~[RegionFileCache.class:?]
        at net.minecraft.world.chunk.storage.AnvilChunkLoader.loadChunk__Async(AnvilChunkLoader.java:98) ~[AnvilChunkLoader.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOProvider.run(ChunkIOProvider.java:68) ~[ChunkIOProvider.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:92) ~[ChunkIOExecutor.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:122) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:93) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.provideChunk(ChunkProviderServer.java:139) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.World.getChunkFromChunkCoords(World.java:355) ~[World.class:?]
        at net.minecraft.world.World.getChunkFromBlockCoords(World.java:347) ~[World.class:?]
        at net.minecraft.world.World.getTileEntity(World.java:2595) ~[World.class:?]
        at minecraftplaye.justanotherenergy.common.tileentities.TileEntityPipeTransferEnergy.onLoad(TileEntityPipeTransferEnergy.java:59) ~[TileEntityPipeTransferEnergy.class:?]
        at net.minecraft.world.chunk.Chunk.addTileEntity(Chunk.java:878) ~[Chunk.class:?]
        at net.minecraft.world.chunk.Chunk.addTileEntity(Chunk.java:855) ~[Chunk.class:?]
        at net.minecraft.world.chunk.storage.AnvilChunkLoader.loadEntities(AnvilChunkLoader.java:519) ~[AnvilChunkLoader.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOProvider.syncCallback(ChunkIOProvider.java:96) ~[ChunkIOProvider.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:94) ~[ChunkIOExecutor.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:122) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:93) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.provideChunk(ChunkProviderServer.java:139) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.World.getChunkFromChunkCoords(World.java:355) ~[World.class:?]
        at net.minecraft.world.World.getChunkFromBlockCoords(World.java:347) ~[World.class:?]
        at net.minecraft.world.World.getTileEntity(World.java:2595) ~[World.class:?]
        at minecraftplaye.justanotherenergy.common.tileentities.TileEntityPipeTransferEnergy.onLoad(TileEntityPipeTransferEnergy.java:59) ~[TileEntityPipeTransferEnergy.class:?]
        at net.minecraft.world.chunk.Chunk.addTileEntity(Chunk.java:878) ~[Chunk.class:?]
        at net.minecraft.world.chunk.Chunk.addTileEntity(Chunk.java:855) ~[Chunk.class:?]
        at net.minecraft.world.chunk.storage.AnvilChunkLoader.loadEntities(AnvilChunkLoader.java:519) ~[AnvilChunkLoader.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOProvider.syncCallback(ChunkIOProvider.java:96) ~[ChunkIOProvider.class:?]
        at net.minecraftforge.common.chunkio.ChunkIOExecutor.syncChunkLoad(ChunkIOExecutor.java:94) ~[ChunkIOExecutor.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:122) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.loadChunk(ChunkProviderServer.java:93) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.gen.ChunkProviderServer.provideChunk(ChunkProviderServer.java:139) ~[ChunkProviderServer.class:?]
        at net.minecraft.world.World.getChunkFromChunkCoords(World.java:355) ~[World.class:?]
        at net.minecraft.world.World.getChunkFromBlockCoords(World.java:347) ~[World.class:?]
        at net.minecraft.world.World.getTileEntity(World.java:2595) ~[World.class:?]
        at minecraftplaye.justanotherenergy.common.tileentities.TileEntityPipeTransferEnergy.onLoad(TileEntityPipeTransferEnergy.java:59) ~[TileEntityPipeTransferEnergy.class:?]

     

        @Override
        public void onLoad() {
        	super.onLoad();
        	
        	// this has to be called as the dc list relies on it
        	if(this.connected.isEmpty()) {
        		this.findTransferPipes();
        		this.flag = true;
        	}
        	
        	// fill the dc list with data
        	if(this.direct_connect.isEmpty()) {
        		for(EnumFacing side : EnumSet.allOf(EnumFacing.class)) {
        			if(side == null) continue;
        			
        			BlockPos neighbour = this.getPos().offset(side);
        			TileEntity tile = this.getWorld().getTileEntity(neighbour); // line 59, how can here even be a stackoverflow exception???
        			if(tile == null) continue;
        			
        			if(tile instanceof TileEntityPipeTransferEnergy) {
        				// the transfer pipe itself should also not be in the list
        				continue;
        			} else if(tile instanceof TileEntityEnergy) {
        				// we don't want to have producers in our list
        				if(((TileEntityEnergy) tile).container.getTransferMode() == EnergyTransfer.PRODUCER)
        					continue;
        			}
        			
        			if(this.connected.containsKey(neighbour))
        				continue;
        			
            		// check the facing of the block to make sure which side is connected to us
        			for(EnumFacing face : EnumFacing.VALUES) {
        				BlockPos offset = this.getPos().offset(face);
        				if(offset == neighbour) {
        					
        					if(EnergyUtils.hasCapability(tile, face))
        						this.direct_connect.put(neighbour, face);
        				}
        			}
        			if(!this.direct_connect.containsKey(neighbour)) {
        				if(EnergyUtils.hasCapability(tile, null)) {
        					this.direct_connect.put(neighbour, null);
        					this.flag = true;
        				}
        			}
        		}
        	}
        }

     

    But interesting with the onLoad method, didn't even know such a method existed.

     

    8 hours ago, Rikka0_0 said:

    PS: Are you making your own energy system?

    Well, I'm making a mod based around energy using Forge Energy (while also supporting Tesla (in theory the Tesla code works ^^)) to be compatible with as many other mods as possible.

    Should be pretty close now to adding all the features in instead of writing tons of background logic and doing research on how x thing works. (Pollution from machines incoming ^^)

  17. On 18.8.2017 at 10:49 PM, jabelar said:

    This type of problem is usually very specific to your code and not everyone has time to debug other peoples code. So I suggest you just debug the problem. The way I debug a problem is to add a lot of console statements (either System.out.println() statements or Logger) at all the key points in the code. I usually put one before each if statement and inside the if statement to prove which path of the code gets executed.

     

    I'm pretty sure if you just print out the energy transfer values at all the points where they are supposed to change, you'll quickly identify which part isn't changing as expected and then you can narrow in to solve the problem.

    Well, that's what I did before posting this post as I actually run into a lot of problems regarding the energy network, so I debugged the whole code the past few days before posting it a few times.

     

    Anyway, after taking a small break, I could track down some of the problems regarding the energy network to a visual problem.

    After having this fixed, I've further tracked the problem down to the BlockTransfer.java class. The code their is not executed when the World gets reloaded, thus

    the list for sending the energy in TileEntityPipeTransferEnergy.java stays emtpy. This means I somehow have to call a similiar code also when the world gets reloaded

    or the Game restarted etc., but I'm not quite sure where to call this code (normally I would call it in onBlockAdded, but the description of this method states it is called before the tile entity gets placed).

    I also don't want to have another if-check in the update-method from my tile entity, if possible.

     

    Then I've also noticed that for some reason the machine (java file) doesn't save the stored energy, but it should store it, as I've overridden the nbt methods to store aditional information, but I am still calling the super methods which save and load the data.

  18. Hi,

     

    I've got the problem with my cables that in some cases they do not send energy into machines or even into other cables. (see the pictures below)

     

    The source code:

    BlockTransfer.java

    TileEntityPipeTransferEnergy.java

    TileEntityEnergy.java (base class)

    machine (java file) 

     

    I basically linked the files in the repository here (1.10.2 branch) as I've got no clue anymore what the problem maybe (after gettings problems after problems xD).

    (Note: It's the 1.10.2 branch as this branch has currently the most up-to-date code online, thought the code base for 1.11 is the same with the same problems.)

     

    Thx in advance.

    Bektor

     

    EDIT:

    I tracked some of the problems down to a visual problem which is now solved. Thus I removed the images which show this problem.

    I've further tracked the remaining problem down to the BlockTransfer.java class. The code their is not executed when the World gets reloaded, thus

    the list for sending the energy in TileEntityPipeTransferEnergy.java stays emtpy. This means I somehow have to call a similiar code also when the world gets reloaded

    or the Game restarted etc., but I'm not quite sure where to call this code (normally I would call it in onBlockAdded, but the description of this method states it is called before the tile entity gets placed).

    I also don't want to have another if-check in the update-method from my tile entity, if possible.

     

    Then I've also noticed that for some reason the machine (java file) doesn't save the stored energy, but it should store it, as I've overridden the nbt methods to store aditional information, but I am still calling the super methods which save and load the data.

    base.png

    base_1.png

    base_2.png

    base_4.png

    base_6.png

    base_3.png

    base_5.png

  19. 10 hours ago, Is.M.L said:

    This extension isn't up-to-date at all, so I'm not so sure how well it will work, but it doesn't work with the newest versions of Visual Studio (like 2017).

    Thought I know there are some extensions available for VS Code which are up-to-date: Java Extendsion, Gradle Extension

     

    For Gradle related things, it seems like you have to change the build.gradle file a bit: 

    https://docs.gradle.org/current/dsl/org.gradle.ide.visualstudio.VisualStudioProject.html

    https://www.visualstudio.com/en-us/docs/build/steps/build/gradle

    https://stackoverflow.com/questions/32592066/how-to-build-visual-studio-project-under-gradle

     

    Thougt it seems to be that you can build Android Apps using VS, so maybe looking into the documentation on how to build Android Apps for VS might help as Android Apps are build using Gradle and Java.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.