Jump to content

kiou.23

Members
  • Posts

    444
  • Joined

  • Last visited

  • Days Won

    5

Posts posted by kiou.23

  1. 13 minutes ago, TheGreyGhost said:

    Howdy.

    Is there any reason you can't create your own IInventory?

    Or a Container to wrap your ItemStackHandler?

    It need to be able to craft any crafting recipe as well, so I would need to use the getRecipe() method, passing IRecipeType.CRAFTING

    but then the IInventory parameter needs to be of CraftingInventory

    or is there a better way to get the recipes?

     

    this is my current code:

    public class ModWorkbenchTileEntity extends TileEntity implements INamedContainerProvider {
    
        final ItemStackHandler craftMatrix = new ItemStackHandler(9);
    
        public ModWorkbenchTileEntity() {
            super(ModTileEntityTypes.MOD_WORKBENCH.get());
        }
    
        private Optional<ICraftingRecipe> getRecipe() {
            ItemStack[] stacks = new ItemStack[9];
            for (int i = 0; i < craftMatrix.getSlots(); i++)
                stacks[i] = (craftMatrix.getStackInSlot(i));
            Inventory inv = new Inventory(stacks);
    
          	// This errors because inv needs to be a CraftingInventory
            return world.getRecipeManager().getRecipe(IRecipeType.CRAFTING, inv, world);
        }
    
    
      	//this is unimplemented and isn't relevant to the issue
        @Override
        public ITextComponent getDisplayName() {
            return null;
        }
    
        @Override
        public Container createMenu(int windowId, PlayerInventory playerInv, PlayerEntity player) {
            return null;
        }
    }

     

  2. you just double click the jar and it should run the installer. you can also right-click and then click open.

    in the installer select install client, and click Ok

    and that should be it

     

    you need to have open Minecraft in the version you're trying to install at least once too

  3. I'm trying to make a tile entity that would have a superset of the Crafting Table functionality. However the Crafting Table doesn't have a Tile Entity, and I'm having a hard time trying to get the Crafting Matrix. The CraftingInventory class requires a container to be passed in, so I tried using an ItemStackHandler, but the world.getRecipeManager().getRecipe() method requires a Crafting Inventory to be passed in to find the recipe. And I just can't see how to get through this.

    any help?

  4. 1 hour ago, Eduardu44 said:

     

    I was talking making a indicator inside a GUI, not on the block texture, and i didn't found tutorials for implement energy I/O on the block that was to be the battery. 

    I think you can do that with capabilities if I'm not mistaken, Forge provides an EnergyCapability even

    and for the indicator you can do that in the render method in your container screen class

  5. First you need to register your feature to the ConfiguredFeature Registry

    Then you can add it to the biome generation through the Biome Loading Event (not the Common Setup)

     

    if you want an example:

    @Mod.EventBusSubscriber(modid = TutorialMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
    public class ModFeatures {
    
        public static ConfiguredFeature<?, ?> ORE_SILVER_CONFIG;
    
        @SubscribeEvent
        public static void setup(FMLCommonSetupEvent event) {
            ORE_SILVER_CONFIG = Registry.register(WorldGenRegistries.CONFIGURED_FEATURE, "ore_silver",
                Feature.ORE.withConfiguration(
                    new OreFeatureConfig(
                        OreFeatureConfig.FillerBlockType.BASE_STONE_OVERWORLD,
                        ModBlocks.SILVER_ORE.get().getDefaultState(), 9)
                ).range(64).square().func_242731_b(20)
            );
        }
    }

     

    @SubscribeEvent
        public void onBiomeLoading(final BiomeLoadingEvent biome) {
            if(biome.getCategory() == Biome.Category.NETHER || biome.getCategory() == Biome.Category.THEEND) return;
    
            biome.getGeneration().getFeatures(GenerationStage.Decoration.UNDERGROUND_ORES)
                .add(() -> ModFeatures.ORE_SILVER_CONFIG);
        }

     

  6. 1 hour ago, diesieben07 said:
    • That is not how you handle exceptions, ever.

    I'm really bad at handling with exceptions, mostly because I have a limited experience with Java. What should I be doing instead?

     

    1 hour ago, diesieben07 said:
    • Because this is a tick event and happens often, you might want to use MethodHandles or an access transformer instead of pure reflection, for performance reasons.

    Makes sense, I don't know what those thing are but I'll look into that

    1 hour ago, diesieben07 said:
    • That is a very inefficient way way to turn an iterable into a List. You should use Lists.newArrayList instead.

    I was looking for a way to convert a Iterable into a List, and this was the first I found, I'll update it then

    1 hour ago, diesieben07 said:
    • Why are you using Iterables.size?

    My bad, I can use the length of the list, just didn't see it amidst the hundreds of times I rewrote this method

  7. On 12/5/2020 at 8:19 PM, diesieben07 said:

    There are algorithms which allow you to pick N random elements from a list, without traversing the whole list. See here for example: https://stackoverflow.com/a/35278327/3638966.

    Alright, something like this?

    	@SubscribeEvent
        public void onWorldTick(final TickEvent.WorldTickEvent event) {
            if (event.side.isClient()) return;
            if (event.phase == TickEvent.Phase.END) return;
    
            ServerChunkProvider serverChunkProvider = (ServerChunkProvider) event.world.getChunkProvider();
    
            Iterable<ChunkHolder> iterable;
    
            try {
                iterable = (Iterable<ChunkHolder>)getLoadedChunksIterable.invoke(serverChunkProvider.chunkManager);
            } catch(Exception e) {
                return;
            }
    
            List<ChunkHolder> chunkHolders =
                    Arrays.stream(Iterables.toArray(iterable, ChunkHolder.class)).collect(Collectors.toList());
    
            int length = Iterables.size(chunkHolders);
            int n = 500;
            if (length < n) n = length;
    
            for (int i = length - 1; i >= length - n; i-- ) {
                Collections.swap(chunkHolders, i, RANDOM.nextInt(i + 1));
            }
    
            for(ChunkHolder chunkHolder : chunkHolders.subList(length - n, length);) {
                Chunk chunk = chunkHolder.getChunkIfComplete();
                if (chunk == null) continue;
    
                ChunkValue chunkValue = chunk.getCapability(ModCapabilities.CHUNK_VALUE_CAP, null).orElse(null);
                if (chunkValue == null) continue;
    
                chunkValue.incrementValue(RANDOM.nextInt(40) == 0 ? 1 : 0);
            }
        }

     

    Having to iterate over the incomplete Chunk Holders just feels inefficient. But it does work

     

  8. you can also use the onBlockActivated method from your block class, and check what item the player is holding.

    Or you can use the onItemUse method from your item class, and check what is the block the item is being used on.

     

    This may be better than listening to the event, because then you're only running code when your item is used or when your block is right-clicked, not on every player Interaction

    • Like 1
  9. 8 minutes ago, diesieben07 said:

    Vanilla uses ChunkHolder#getTickingFuture().getNow(ChunkHolder.UNLOADED_CHUNK).left() and then checks Optional#isPresent on the result before ticking chunks. Using getChunkIfComplete and using a null check comes down to the same thing.

    Hold on, can I subscribe to a Chunk Tick Event? That would really simplify things, but There is no ChunkTickEvent in the TickEvent

    actually, is the WorldTickEvent even what I should be using?

    (Also, I heard that the tick event is called twice, one for each phase, so I should check the phase before running right? for what phase should I check, does it make a difference?)

     

    8 minutes ago, diesieben07 said:

    Not really, no. You would only pick a few values out of a list and work on those, instead of handling all of them.

    This isn't realted to Forge, but I don't see how I would do this? would if I iterate, say, through only 20% of the chunks wouldn't the other 80% never be updated? or is the Iterable in a random order every time?

     

    Edit: There is a ChunkEvent, does that help me?

  10. 11 hours ago, diesieben07 said:

    To safely get all loaded chunks you need to use ChunkManager#getLoadedChunksIterable. It also requires reflection, but accessing the fields directly is not threadsafe, as they are also used from the chunk loading thread.

    Yeah, that's what I was using at first, but if I looped through all valeus of the Iterable it would have about 2000 to 3000 ChunkHolders, and more than half of them would be null (I think the ChunkHolder wasn't null, but returned null when I tried to get the chunk using getChunkIfComplete).

    Then after looking at the Chunk Manager class I found the loadedPositions field, which seemed to only contain the position of the ChunkHolders that were completed.

    But if I should use the getLoadedChunksIterable, then what should I do to not waste loop iterations on ChunkHolders that would return null? or is ChunkHolder#getChunkIfComplete not the correct method to use?

     

    11 hours ago, diesieben07 said:

    Instead of getting all chunks and checking for each if you want to increment their value, instead pick a percentage of the loaded chunks and increment just their values. That way you have to loop through a lot less to achieve the same effect.

    Wouldn't I have to iterate trough alll chunks in the same way tho?

  11. Okay, I thought I had solved it

    but the the way I did it is very innefective

    I tried getting the loadedPositions from ChunkManager, and pass it into a method that returns the Chunk from the pos as a long:

    public void onTick(final TickEvent.WorldTickEvent event) {
            ChunkManager chunkManager = ((ServerChunkProvider) event.world.getChunkProvider()).chunkManager;
    
            LongSet loadedPositions;
    
            try {
                loadedPositions = (LongSet)loadedPositionsField.get(chunkManager);
            } catch (Exception e) {
                LOGGER.error("Error on TickEvent Handler (loadedPositions): " + e.getMessage());
                return;
            }
      
            for (Long pos : loadedPositions) {
    
                ChunkHolder chunkHolder;
                try {
                    chunkHolder = (ChunkHolder)getLoadedChunkMethod.invoke(chunkManager, pos);
                } catch (Exception e) {
                    LOGGER.error("Error on TickEvent Handler (getLoadedChunk): " + e.getMessage());
                    continue;
                }
                Chunk chunk = chunkHolder.getChunkIfComplete();
                if (chunk == null) continue;
    
                ChunkValue chunkValue = chunk.getCapability(ModCapabilities.CHUNK_VALUE_CAP, null).orElse(null);
                if (chunkValue == null) {
                    LOGGER.error("chunkValue is null");
                    continue;
                }
    
                chunkValue.incrementValue(RANDOM.nextInt(200) == 0 ? 1 : 0);
            }
        }

    But it erroed when trying to get the loadedPositions

     

    can anyone help with this?

    or additionally, is there a better way to do this? that doesn't require getting the loaded chunks at all?

  12. 27 minutes ago, Turtledove said:

    Ugly conditionals, as in:

    
    switch key:
    	case 'blah':
    		return BlahEntity object
    	case 'foo':
    		return FooEntity object
    	case 'bar':
    		return BarEntity object
    	.
    	.
    	.
    	case 'blah':
    		return BlahEntity object

    Where I'd need to add to this whenever I add new relevant Entities. This is what I'm avoiding.

    Can't you make the method generic? make it receive a EntityType<T> and then return the entity from it

    It also seems very redundant, why do you need a method for this, isn't it easier to call EntityRegistry.RANDOM_ENTITY_TYPE.get().create()?

     

    I also don't get why you are using reflections. I suppose you're using Deferred Registries, and the Deferred Regsitry has a method that returns all entries. And if you're not using Deferred Registries, you should

  13. 22 minutes ago, Turtledove said:

    It correctly retreives the EntityTypes, the problem is that I don't know how to get an Entity object out of it.

    You can use EntityType.create(), this returns a new Entity

     

    23 minutes ago, Turtledove said:

    This part works just fine, we pass null to field.get() in this case because the members it's looking for are static.

    Oh yeah, those are static, my bad. It's that I just spended the whole day doing reflection and getting non static values

  14. 1 hour ago, Turtledove said:

    Sidenote: I'm trying to do it this way because I don't want to create a giant conditional statement since it would not scale well at all with my project's scope.

    I don't see in which scenario not using reflection would result in a giant conditional statement

     

    1 hour ago, Turtledove said:

    and when I need an entity to spawn I simply call the following method where I try to return an entity via a string key.

    Trying to get things by string is very error-prone, you should at a minimun store the Entity Id String in your EntityRegistry as a static final, and then use it when needed

  15. Okay...

    first thing wrong is with your reflection code: you are passing null into the .get() method, that's not how it works.

    you need to pass it an instance of the Object that you got the Field from, in this case you need the instance of EntityRegistry.

     

    But there's a way better way of accomplishing what you want, you can just get the Deffered Register from your EntityRegistry class, and it has a method called .getEntries(), I think it's pretty self explanatory what it does.

     

    This should solve your problem and drastically simplify the code

  16. Sorry buddy, 1.7 isn't supported in this forum anymore, you really should update

     

    (However, it seems the problem may be that you're just missing a core mod, something related to xreliquary? edit: after reading the crash log a bit more, I have no idea)

  17. Hmm, seems that the problem is with replacing vanilla blocks and adding more states to them, I think forge doesn't like that... and I haven't tried to replace anything in vanilla
    I found this thread on the forum: https://forums.minecraftforge.net/topic/71283-1132-vanilla-block-replacement/

    may be a bit old but seems like the OP was having the same problem, maybe it helps

     

    Maybe make a new Cauldron Block and just replace the recipe to return your block?

     

  18. Can you share your Registry code and your Mod main class?

     

    27 minutes ago, <Gl33p_0r4nge> said:

    It is not always 0 it stores the material in the cauldron

    I'm talking about this snippet:

    @Nullable
    @Override
    public BlockState getStateForPlacement(BlockItemUseContext context) {
    	return this.getDefaultState().with(CONTENT, 0).getBlockState();
    }

    this function return the state for placement based on the context of the placement, it's useful so you can orient a directional block for example, but in this case it always return the same block state independent of the state, so it's redundant

    this clearly isn't the problem that's causing the crash tho

     

    The crash log doesn't say anything about the State Container crashing, it says the error ocurred when registering, did you alter something in the registration before it started crashing?

     

  19. So I have a class attached to the chunks through capabilities, and I want to update the values in world tick. I have an event subscriber for the TickEvent.WorldTickEvent event, but I don't know how to get the loaded chunks. I would also need access to multiple chunks at once, as the value for a chunks next state would depend on it's neighbours

     

    Edit: I solved it myself, took me a few hours...

    If anyone croses this topic and is also looking how to do it (I stripped the code to only contain the relevant snippets):

     

    @Mod(TutorialMod.MOD_ID)
    public class TutorialMod
    {
        public static final String MOD_ID = "tutorial";
    
        public static final Logger LOGGER = LogManager.getLogger();
        public static final Random RANDOM = new Random();
    
        public static final Method getLoadedChunksMethod;
    
        public TutorialMod() {
            IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
    
            modEventBus.addListener(this::setup);
    
            MinecraftForge.EVENT_BUS.register(this);
        }
    
    
        public void setup(final FMLCommonSetupEvent event) {
            if (getLoadedChunksMethod == null) {
                LOGGER.error("getLoadedChunksMethod: Chunk Reflection didn't work!");
                return;
            }
            getLoadedChunksMethod.setAccessible(true);
        }
    
        @SubscribeEvent
        public void onTick(final TickEvent.WorldTickEvent event) {
            World world = event.world;
    
            ServerChunkProvider serverChunkProvider = (ServerChunkProvider) world.getChunkProvider();
    
            try {
                Iterable<ChunkHolder> chunks = (Iterable<ChunkHolder>)getLoadedChunksMethod.invoke(serverChunkProvider.chunkManager);
    
                chunks.forEach(chunkHolder -> {
                    Chunk chunk = chunkHolder.getChunkIfComplete();
                    if (chunk == null) return;
                    ChunkValue chunkValue = chunk.getCapability(ModCapabilities.CHUNK_VALUE_CAP, null).orElse(null);
                    if (chunkValue == null) {
                        LOGGER.error("chunkValue is null");
                        return;
                    }
                    chunkValue.incrementValue(RANDOM.nextInt(200) == 0 ? 1 : 0);
                });
    
            } catch (Exception e) {
                LOGGER.error("Error on TickEvent Handler: " + e.getMessage());
                return;
            }
        }
    
        private static Method getGetLoadedChunksMethod() {
            try {
                return ChunkManager.class.getDeclaredMethod("getLoadedChunksIterable");
            } catch (Exception e) {
                LOGGER.error("Exception in getGetLoadedChunksMethod: " + e.getMessage());
                return null;
            }
        }
    
        static {
            getLoadedChunksMethod = getGetLoadedChunksMethod();
        }
    }

     

×
×
  • Create New...

Important Information

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