Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Slit_bodmod

Members
  • Joined

  • Last visited

Everything posted by Slit_bodmod

  1. So I've been working on an experimental mod recently, trying to structure the registry side of my mod in a different way (hence 2 forum questions in basically as many days). So I have this class here that is supposed to ease with the registering of blocks and block items that looks like this: public class BlockItemRegister<B extends Block> implements Supplier<B> { public final Supplier<B> block; public final Supplier<Item> item; public BlockItemRegister(Supplier<B> _block, Supplier<Item> _item) { block = _block; item = _item; } public BlockItemRegister(String id, Supplier<B> _block, Item.Properties prop) { this(_block, ModItems.register(id, () -> new BlockItem(_block.get(), prop)) ); } public BlockItemRegister(String id, Supplier<B> _block) { this(id, _block, new Item.Properties().tab(ItemGroup.TAB_BUILDING_BLOCKS)); } public B get() { return block.get(); } //--------- method created to scare away some generic weirdness public static <B extends Block> BlockItemRegister<B> gen(String id, Supplier<B> _block) { return new BlockItemRegister<>( id, ModBlocks.registerBlock(id, _block ) ); } public static <B extends Block> BlockItemRegister<B> gen(String id, Supplier<B> _block, Item.Properties prop) { return new BlockItemRegister<>( id, ModBlocks.registerBlock(id, _block ), prop ); } public static <B extends Block> BlockItemRegister<B> gen(String id, Supplier<B> _block, Supplier<Item> _item) { return new BlockItemRegister<>( ModBlocks.registerBlock(id, _block ), _item ); } } This references this function in the ModBlocks class: public static <B extends Block> RegistryObject<B> registerBlock(String name, Supplier<B> block) { return BLOCKS.register(name , block); } and this one in ModItems: public static <I extends Item> RegistryObject<I> register(String name, Supplier<I> item) { return ITEMS.register(name , item); } which is fairly straightforward. I can then register a block item like this and it works fine: BlockItemRegister<RotatedPillarBlock> log = BlockItemRegister.gen( id, () -> new RotatedPillarBlock(ModBlockProperties.LOG), ModItems.withTab(ItemGroup.TAB_BUILDING_BLOCKS)); however if I do this: Supplier<DoorBlock> door_block = () -> new DoorBlock(ModBlockProperties.PLANKS); BlockItemRegister<DoorBlock> doorBlock = BlockItemRegister.gen( id, door_block, ModItems.register( id, () -> new TallBlockItem(door_block.get(), ModItems.withTab(ItemGroup.TAB_REDSTONE) ))); the block item register holds the door item however when I call .asItem() on the block it returns air which is causing me crashes. I'm struggling to understand why this might be as theoretically these are basically calling the same functions just with and without default functions
  2. No sry I don't have a git repo as this is a bit of an experiment mod, I can try creating a one if it's really necessary but for the moment this is the class that handles the loot tables: public class GaiaBlockLootTables extends BlockLootTables { public static final List<Consumer<GaiaBlockLootTables>> TABLES = new ArrayList<>(); @Override protected void addTables() { TABLES.forEach( (gen) -> gen.accept(this) ); } @Override protected @Nonnull Iterable<Block> getKnownBlocks() { return ModBlocks.BLOCKS.getEntries().stream().map(RegistryObject::get).collect(Collectors.toList()); } //=========================================== METHODS ======================================================================= public void add(Block _block, LootTable.Builder _builder) { super.add(_block,_builder); } public void accept(BiConsumer<ResourceLocation, LootTable.Builder> p_accept_1_) { super.accept(p_accept_1_); } public void dropSlab(Block block) { this.add(block, createSlabItemTable(block)); } } this is then registered through this class: public class GaiaLootTableGenerator extends LootTableProvider { public GaiaLootTableGenerator(DataGenerator dataGeneratorIn) { super(dataGeneratorIn); } @Override protected @Nonnull List<Pair<Supplier<Consumer<BiConsumer<ResourceLocation, LootTable.Builder>>>, LootParameterSet>> getTables() { return ImmutableList.of( Pair.of(GaiaBlockLootTables::new, LootParameterSets.BLOCK) ); } } which is registered through this class: @Mod.EventBusSubscriber(modid = GaiaTerrainMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class GaiaDataManager { @SubscribeEvent public static void gatherData(final GatherDataEvent event) { GaiaTerrainMod.LOGGER.info("gathering data!"); DataGenerator generate = event.getGenerator(); ExistingFileHelper existingFileHelper = event.getExistingFileHelper(); generate.addProvider(new GaiaBlockStateGenerator(generate,existingFileHelper)); generate.addProvider(new GaiaItemModelGenerator(generate, existingFileHelper)); GaiaBlockTagGenerator blockTags = new GaiaBlockTagGenerator(generate, existingFileHelper); generate.addProvider(blockTags); generate.addProvider(new GaiaItemTagGenerator(generate, blockTags, existingFileHelper)); generate.addProvider(new GaiaLootTableGenerator(generate)); generate.addProvider(new GaiaRecipeGenerator(generate)); GaiaTerrainMod.LOGGER.info("gathered data!"); } } and then there are these snippets throughout my code base that do something like this: GaiaBlockLootTables.TABLES.add( (instance) -> instance.dropSelf(button.get()) ); this allow my loot tables to be generated somewhat automatically from a number of different places (my registry system is kinda unconventional)
  3. Right yeah I wanted to but obviously I can't show you the whole thing, where should I show first that might be causing the issue as tbh my main problem is I don't know where to start looking, do you know what would cause this error
  4. So I've been messing around with data generators and I've gotten pretty far but then just before everything seemed like it was working I got this crash So I looked at the logs and it seemed to indicate that the problem was with vanilla loot tables? I kinda reached the end of my train here and was just looking for any pointers as to where to start fixing this kinda issue cause it seems a little odd to me
  5. oh the crash seems to be caused by the fact I'm missing a texture, is that not allowed
  6. haha, that made it start crashing which is progress!
  7. I hadn't done that actually but now I have and it's not made any difference as far as I can tell.
  8. Hey, I'm new to the forge data generators and was trying to get them up and running. At the moments they aren't crashing or anything but they also don't seem to be generating any data, as far as I can tell they're set up correctly and I've tried both runClient and runData and as far as I can tell they neither loaded the models correctly into the game nor output them in any files I can see. I have no real idea what I'm doing though. so I have my main data generator class that looks a bit like this: @Mod.EventBusSubscriber(modid = GaiaTerrainMod.MODID, bus = Mod.EventBusSubscriber.Bus.MOD) public class GaiaDataManager { @SubscribeEvent public static void gatherData(final GatherDataEvent event) { GaiaTerrainMod.LOGGER.info("gathering data!"); DataGenerator generate = event.getGenerator(); ExistingFileHelper existingFileHelper = event.getExistingFileHelper(); generate.addProvider(new GaiaBlockStateGenerator(generate,existingFileHelper)); generate.addProvider(new GaiaItemModelGenerator(generate, existingFileHelper)); GaiaBlockTagGenerator blockTags = new GaiaBlockTagGenerator(generate, existingFileHelper); generate.addProvider(blockTags); generate.addProvider(new GaiaItemTagGenerator(generate, blockTags, existingFileHelper)); generate.addProvider(new GaiaLootTableGenerator(generate)); generate.addProvider(new GaiaRecipeGenerator(generate)); GaiaTerrainMod.LOGGER.info("gathered data!"); } } originally it didn't have the "@Mod.EventBusSubscriber(modid = GaiaTerrainM..." line at the top and instead was only invoked through a line in the GaiaTerrainMod constructor that looked like this: public GaiaTerrainMod() { IEventBus registry_bus = FMLJavaModLoadingContext.get().getModEventBus(); registry_bus.addListener(this::setup); MinecraftForge.EVENT_BUS.register(this); MinecraftForge.EVENT_BUS.register(GaiaDataManager.class); ModWoodTypes.init(); ModBlocks.BLOCKS.register(registry_bus); ModItems.ITEMS.register(registry_bus); GaiaBiomeSelector.initBiomeMappings(); } as you can see at the start and end of my gatherData function I have logs and when I hit "runData" they fired and I could see them as the last 2 things outputted by the console, however in GaiaBlockStateGenerator, the first data provider added to my data generator, I also put 2 logs at the start and end of the overriden registerStatesAndModels() function. These never fired, I assume they should after my gatherData logs fired. Not sure though, as far as i can tell the issue should be somewhere in these files (unless it's somewhere weird), again I'm not getting any crashes or errors just a plain old, doesn't do the thing I want it to which clearly indicates I've done something dumb somewhere.
  9. Hey I was wondering how if say you had a particular nbt file you wanted to be compiled with your mod in the data folder, how I could then read that file from the mod's resources in code, and if it's automatically checked whether it's overridden by datapacks that match that paticular file structure, and if not how you can do that?
  10. Ok cool, I changed it to something like this: public InteriorStyle getIntStyle() { try { tardis_lock.readLock().lock(); InteriorStyle ret_style = int_style; return ret_style; } finally { tardis_lock.readLock().unlock(); } } if there is any lock you would recommend over ReentrantReadWriteLock I'd be happy to use that, other wise you have been super helpful and I am very grateful
  11. Ok so I the version I am currently using looks a bit like this. I still have something that looks like this in order to pull a TardisManager. public static final Map<World,TardisManager> INSTANCES = new MapMaker().weakKeys().makeMap(); and the TardisManager contains this map. private final ConcurrentHashMap<Integer,Tardis> ALL_TARDISES = new ConcurrentHashMap(); so I can then pull a tardis object, I then have some stuff that looks like this inside of the Tardis class private ReentrantReadWriteLock tardis_lock; public InteriorStyle int_style; public InteriorStyle getIntStyle() { tardis_lock.readLock().lock(); InteriorStyle ret_style = int_style; tardis_lock.readLock().unlock(); return ret_style; } public void setIntStyle(InteriorStyle new_style) { tardis_lock.writeLock().lock(); int_style = new_style; tardis_lock.writeLock().unlock(); } and that returns an InteriorStyle object which is an enum so all fields are final. Is that what I'm supposed to do?
  12. Yeah maybe it would be a better idea to have a separate immutable struct inside of my TardisManager.Tardis called TardisGenerationInfo or something that was always written in a thread safe way and was the only thing that the chunk generator was allowed to read from. So the reference to tardisManager is gotten through a ConcurrentMap, as well as the reference to the specific Tardis. so maybe this new object is stored in a separate hash map, or a reference to it can only be used from within the Tardis data structure and contains basically an immutable structure that be accesed by the chunk generator and if any of the data updates, a lock is clicked denying read access, the reference is replaced with a new instance of TardisGenerationInfo and then the lock is unlocked. actually if I made a system like this would I need to make it all immutable fields each read and write into this class was dependent on the lock.
  13. yes but will it stop me getting thread issues when reading and writing to that hash map? right, I gather the best way to go about doing this is with getters and setters for every variable (aaargh), and also locking and unlocking the read locks at the start of all functions, does this include the constructors, I assume not. I assume I do at the start of my serialisation function. also am I right to assume that the syntax for the locks is: my_class_lock.readLock().lock() my_class_lock.readLock().unlock() my_class_lock.writeLock().lock() my_class_lock.writeLock().unlock() and I use the read locks for reading, write locks for writing, lock at the start and unlock at the end
  14. No, I think if I make the underlying data structure in my TardisManager using a MapMaker it will be fine. As for using the ReentrantReadWriteLock appropriately. I assume I should lock it at the beginning of the copy constructor and unlock it at the end. What impact will this have. when I read/write to the other fields in my data structure, I assume it won't automatically be safe, do they have lock it first and then write to the data strucuture?
  15. right, well the trouble with creating a copy on the main thread is that the data is going to be modified as the world is running, particularly from the overworld (seeing as this chunk generator is designed to work for a specific dimension). so ideally I need the data to be the most up to date the moment I create a new chunk. That being said if the data changes while the chunk is being generated (or preferably when the region is being generated), the main thread still needs to keep track of that but I don't want the chunk generator to have its copy changed. So getting a hold of the TardisManager is done through a thread safe map atm. Getting a reference to the specific tardis required is currently done from a non-thread safe map so can I just make it a thread safe map and that will be fine. If so then real difficulty seems to be then getting all of the data from the Tardis object that map holds a reference too. As discussed the best way to do that is to try and create a copy of it in a thread safe manor for use by the chunk generator. The question obviously is how. I presume then synchronised won't help me out here as I can't make every function that writes into this data structure so I need to somehow lock the whole datastructure for writing at the start of the copy function and unlock it at the end, how do you think I might do this? If this is the case should I remove synchronised from getThreadedTardisForPos function?
  16. ah right, so the Tardis manager contains a few different get functions for different Tardises, will they all need to be synchronised, will this impact performance as it's only this one niece case where they need to be accessed by another thread. getTardisForBlock returns a TardisManager.Tardis. the constructor that takes for TardisManager.Tardis that takes in another TardisManager.Tardis is basically just a copy constructor that returns a new object with the same values for this thread to modify and read. in-fact the Tardis manager stores all instances of Tardis that the program ever uses inside of a map, all constructors for the Tardis are default accessibility because of this (except for the copy constructor which is public). If I made this map using "new MapMaker().makeMap()" would that help maybe. As for TardisManager.Tardis, not all fields are mutable, including some I need for the chunk generator can be changed in code, however I don't really want these values changing during the generation of a given chunk atleast for the Tardis object that it's working on (which is why I made the function return a new copy) Essentially would it make sense for me to have some synchronised function(or block in a function) that takes the Tardis from the original map and copies it in a thread safe manor. Would it help if I sent the TardisManager.Tardis file, it's quite long as it also contains some relevant maths and networking functions so I could just send the necessary excerpts?
  17. Oh also that enum I was talking about. So the attribute I need from that is a structure Template stored as a const variable within each instance of an enum. It thus only gets written to when the class is first inited and doesn't get edited beyond that so is that thread safe? just for clarity, it's an enum that a reference to is stored in TardisManager.Tardis containing a constant field of type Template
  18. ok so obviously I have a line of code that says this public static final Map<World,TardisManager> INSTANCES = new MapMaker().weakKeys().makeMap(); then I have my init function that looks like this @SubscribeEvent public static void onWorldLoading(AttachCapabilitiesEvent<World> event) { World world = event.getObject(); DWMCMod.LOGGER.error("attaching capabilities"+world); if (world instanceof ServerWorld) { ServerWorld accessWorld = world.getServer().getWorld(DWMCDimensions.TARDIS_WORLD_KEY); TardisManager tardisManager = getTardisManagerForWorld(accessWorld); INSTANCES.put(accessWorld,tardisManager); } } as you can probably guess, TardisManager is the WorldSavedData, it's basically a wrapper for a map that stores instances of Tardis which is kinda simple value struct, it's pretty much entirely primitive types (although it does contain an enum I'm going to have to pull an attribute from) my only function that is synchronised thus, it is the one that pulls the tardis from the tardis manager public synchronized TardisManager.Tardis getThreadedTardisForPos(IWorld world, BlockPos pos) { if (world instanceof IServerWorld) { ServerWorld server = ((IServerWorld)world).getWorld(); TardisManager manager = INSTANCES.get(server); return new TardisManager.Tardis(manager.getTardisForBlock(pos)); } DWMCMod.LOGGER.error("this shouldn't not be a server world I hope"); return null; } this is what that looks like, again, as you can probably guess, the TardisManager.Tardis constructor that takes in another TardisManager.Tardis is basically a copy constructor. it gets only once at the start of the fillFromNoise method in the chunk and the object it returns (that hopefully shouldn't interfere with other threads). I think that's everything right?
  19. ok so would it work if I just put and get objects from my map as though everything was normal. and then once I've got my reference I need to write a synchronised method that will pull the data I need and return it to the chunk generator. (I'm only gonna need to pull one object so I think it would it be better for the synchronised function and return a deep copy?) Also how do I get the ServerWorld from the IWorld, there isn't a function defined called getLevel, nor any function that returns a ServerWorld as far as I can see.
  20. Hi sorry for late response, Ok so I should create a map<World,WorldSavedData> that when a World Capability is attached will thread lock, and add a mapping of that world to it's appropriate savedData Then in my chunk generator, using IWorld.getLevel() (on an instance ofc), I can look it up in the map and modify it at will, and if I ever do need to write to it for whatever reason I need to lock it first. If this is true what system would you recommend to keep the variables safe? Should I use a java Lock class for the functionality I stated above or make the map volatile or reading data from the map synchronised?
  21. yes there's a priority system, would your item work using a supplier as that's probably the best way to do it
  22. ok, thankyou that's very helpful. I have begun work implementing it and was wondering if I could ask a few questions? - Would the values of my map also want to be weak as I presumably am also storing in the way that WorldSavedData automatically does so I don't want a copy of it to be stored -Will the reference in my map remain a reference, there is a good chance that the main thread will change the contents of my WorldSavedData and Ideally the chunkGenerator should respond to these changes appropriately - I don't know much about the internal structure of the jvm threading but seeing as I can guarantee that my ChunkGenerator won't be writing to the WorldSavedData, only reading, is there any chance of the multiple threads causing issues in this case -yes, would utilising the unsafe class be a good idea and how best can I go about it -Also purely out of interest, would this system have been easier if I'd used capablities or mixins?
  23. well what kind of alternatives are there for having level saveable data that my chunk generator can use, is there a way for me to pass other parameters into the constructor. Or a way for me to send data of any kind across the two threads. Maybe by saving a copy of the data statically somewhere and setting up appropriate checks around it?
  24. Ah that makes a lot of sense, thankyou, so what would you recommend in order for me to get an instance of my worldSavedData object in time for chunk loading to begin? is there some way I can make sure that the chunk generator has an instance of this object before the process begins or some way to reach across in a safe manor?
  25. Hi, sorry small topic but I am writing a custom chunk generator and in order for the generation to work properly I need to access some data stored in world saved data, and thus I need a serverWorld object, at first I starting by casting the IWorld object I am handed in the function I need it for (fillFromNoise aka func_230352_b_) into a ServerWorld and using that, it didn't work, so clearly I must be getting some different world object in the chunk generator. My question is which world object am I getting and how do I convert or access it's associated ServerWorld object safely?

Important Information

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

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.