Jump to content

[Version 1.18.2, SOLVED] Add custom ambient sound to silent mobs (with a little help from capabilities)


Recommended Posts

Posted (edited)

Hello,

I am wondering how I would add ambient sounds to "silent" mobs (such as iron golems, snow golems, and players). I was looking at this forum and I have some questions...

Suppose I want to add ambient noises to iron golems. Do I have to use an event handler that takes in a TickEvent.ServerTickEvent argument? And In order to get all iron golems to be able to emit noises, how would I get a list of all registered iron golems?

Edited by LeeCrafts
  • LeeCrafts changed the title to [Version 1.18.2] Add custom ambient sound to (silent) mobs
Posted (edited)

Update: Don't use this solution. See my bottom comment for a solution involving capabilities.

 

My solution works, but for those who are asking the same questions, this is a bit more complex than we wish it to be.

If you want to add ambient noises to iron golems for example, you would first need to store each iron golem's relevant data in a list. The relevant data includes its UUID string and tick counter (an int value initialized at 0). I recommend using an extra class for this!

Now you must make two event handlers. One handles EntityJoinWorldEvent events, and it checks if event.getEntity() is an iron golem. If so, then add its data to the list. 

The other event handler handles LivingUpdateEvent events, which--as @diesieben07 mentioned--fires every tick (entities get updated every tick). Get the UUID of the entity being updated (event.getEntity().getStringUUID()), and search through the list to get the matching entity data, aka. the list entry containing the same UUID. Increment that entry's tick counter, and if it reaches an x amount of ticks, then play the noise and reset the counter.

 

Side note: Your LivingUpdateEvent handler probably should check if the entity (iron golem) has died, and if it has, then remove its respective entry from the list.

 

I hope my solution is not unnecessarily complicated.

Edit: maybe hash maps are more efficient than lists, but I’ll have to check and come back later. 

Edited by LeeCrafts
Posted (edited)

I just made a working solution with capabilities and it was one hell of a learning experience. There were many tutorials I had to follow because they were mostly from earlier versions. Below is an example code for anyone else who wants to add ambient noises to silent mobs--and learn how to use custom capabilities.

I attach a custom capability (TimeCounter) to iron golems, making each store their own time counter. The counter gets incremented every tick, and once it reaches a certain limit, the iron golem plays a sound and the counter is reset.

 

// must have an interface
public interface ITimeCounter {
    void incrementCounter();
    void resetCounter();
    void rollLimit();
}

 

// ...and a class implementing the interface
public class TimeCounter implements ITimeCounter {
    public int counter; // current tick counter
    public int limit; // number of ticks counter must reach for the sound to be played
    public TimeCounter() {
        counter = 0;
        rollLimit();
    }
    @Override
    public void incrementCounter() {
        this.counter++;
        if (counter < 0) resetCounter();
    }
    @Override
    public void resetCounter() { this.counter = 0; }
    @Override
    public void rollLimit() {
        // adds randomness to limit
        Random random = new Random();
        this.limit = random.nextInt(100) + 100;
    }
}

 

// provides the capability
public class TimeCounterProvider implements ICapabilitySerializable<CompoundTag> {

    private final TimeCounter timeCounter = new TimeCounter();
    private final LazyOptional<ITimeCounter> timeCounterLazyOptional = LazyOptional.of(() -> timeCounter);

    @NotNull
    @Override
    public <T> LazyOptional<T> getCapability(@NotNull Capability<T> cap, @Nullable Direction side) {
        return timeCounterLazyOptional.cast();
    }

    // exclude serializeNBT() and deserializeNBT() if you don't need to persist the data
    // (in that case, also replace ICapabilitySerializable interface with ICapabilityProvider)
    @Override
    public CompoundTag serializeNBT() {
        if (ModCapabilities.TIME_COUNTER_CAPABILITY == null) {
            return new CompoundTag();
        }
        CompoundTag nbt = new CompoundTag();
        nbt.putInt("counter", timeCounter.counter);
        nbt.putInt("limit", timeCounter.limit);
        return nbt;
    }

    @Override
    public void deserializeNBT(CompoundTag nbt) {
        if (ModCapabilities.TIME_COUNTER_CAPABILITY != null) {
            timeCounter.counter = nbt.getInt("counter");
            timeCounter.limit = nbt.getInt("limit");
        }
    }

    // invalidates capability
    public void invalidate() {
        timeCounterLazyOptional.invalidate();
    }
}

 

public class ModCapabilities {

    // instance of the capability
    public static Capability<ITimeCounter> TIME_COUNTER_CAPABILITY = CapabilityManager.get(new CapabilityToken<>(){});
  
    // can put other capabilities here

}

 

@Mod.EventBusSubscriber(modid = MyMod.MOD_ID)
public class ModEvents {

    // registers the capability
    @SubscribeEvent
    public void registerCapabilities(RegisterCapabilitiesEvent event) {
        event.register(ITimeCounter.class);
    }

    // attaches the capability to iron golems
    @SubscribeEvent
    public static void onAttachCapabilitiesEvent(AttachCapabilitiesEvent<Entity> event) {
        if (event.getObject() instanceof IronGolem && !event.getObject().getCommandSenderWorld().isClientSide) {
            TimeCounterProvider timeCounterProvider = new TimeCounterProvider();
            event.addCapability(new ResourceLocation(MyMod.MOD_ID, "time_cap"), timeCounterProvider);
            event.addListener(timeCounterProvider::invalidate);
        }
    }

    // entities get updated every tick
    @SubscribeEvent
    public static void ironGolemSound(LivingEvent.LivingUpdateEvent event) {
        Entity entity = event.getEntity();
        if (entity instanceof IronGolem && !entity.level.isClientSide()) {
            entity.getCapability(ModCapabilities.TIME_COUNTER_CAPABILITY).ifPresent(iTimeCounter -> {
                TimeCounter timeCounter = (TimeCounter) iTimeCounter;
                timeCounter.incrementCounter();
                // when the counter reaches the limit, sound is played
                if (timeCounter.counter >= timeCounter.limit) {
                    entity.playSound(ModSounds.IRON_GOLEM_GRUNT.get(), 1.0F, 1.0F);
                    // entity.level.playSound(null, entity.getX(), entity.getY(), entity.getZ(), ModSounds.IRON_GOLEM_GRUNT.get(), SoundSource.AMBIENT, 1.0F, 1.0F);
                    timeCounter.resetCounter();
                    timeCounter.rollLimit();
                }
            });
        }
    }
}

 

Sources I mainly used: 

https://www.planetminecraft.com/blog/forge-tutorial-capability-system/

https://mcforge.readthedocs.io/en/1.18.x/datastorage/capabilities/

https://forums.minecraftforge.net/topic/106325-1171-forge-capability-how-to-save/

Edited by LeeCrafts
  • LeeCrafts changed the title to [Version 1.18.2, SOLVED] Add custom ambient sound to silent mobs (with a little help from capabilities)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • Yep I did upgrade just because it showed me a new version available.  I'll redownload the mod list and make sure anything works.  Thanks!
    • The latest log was taken down by pastebin for some reason. Did you try removing the mods you added? The mods you updated, was there a specific reason you updated, or just because? It's possible the updates introduced incompatibilitie, or even need a newer build of forge. If you didn't need the updates for a specific reason, you could also try downgrading those mods.
    • Please read the FAQ, and post logs as described there. https://forums.minecraftforge.net/topic/125488-rules-and-frequently-asked-questions-faq/
    • I am using forge 1.20.1 (version 47.3.0). My pc has an RTX 4080 super and an i9 14900 KF, I am on the latest Nvidia graphics driver, latest windows 10 software, I have java 23, forge 1.12.2 works and so does all vanilla versions but for some reason no version of forge 1.20.1 works and instead the game just crashes with the error code "-1." I have no mods in my mods fodler, I have deleted my options.txt and forge.cfg files in case my settings were causing a crash and have tried removing my forge version from the installations folder and reinstalling but no matter what I still crash with the same code and my log doesn't tell me anything: 18:34:53.924 game 2025-02-06 18:34:53,914 main WARN Advanced terminal features are not available in this environment 18:34:54.023 game [18:34:54] [main/INFO] [cp.mo.mo.Launcher/MODLAUNCHER]: ModLauncher running: args [--username, mrmirchi, --version, 1.20.1-forge-47.3.0, --gameDir, C:\Users\aryam\AppData\Roaming\.minecraft, --assetsDir, C:\Users\aryam\AppData\Roaming\.minecraft\assets, --assetIndex, 5, --uuid, 2db00ea8d678420a8956109a85d90e9d, --accessToken, ????????, --clientId, ZWI3NThkNzMtNmNlZS00MGI5LTgyZTgtYmZkNzcwMTM5MGMx, --xuid, 2535436222989555, --userType, msa, --versionType, release, --quickPlayPath, C:\Users\aryam\AppData\Roaming\.minecraft\quickPlay\java\1738838092785.json, --launchTarget, forgeclient, --fml.forgeVersion, 47.3.0, --fml.mcVersion, 1.20.1, --fml.forgeGroup, net.minecraftforge, --fml.mcpVersion, 20230612.114412] 18:34:54.027 game [18:34:54] [main/INFO] [cp.mo.mo.Launcher/MODLAUNCHER]: ModLauncher 10.0.9+10.0.9+main.dcd20f30 starting: java version 17.0.8 by Microsoft; OS Windows 10 arch amd64 version 10.0 18:34:54.132 game [18:34:54] [main/INFO] [ne.mi.fm.lo.ImmediateWindowHandler/]: Loading ImmediateWindowProvider fmlearlywindow 18:34:54.191 game [18:34:54] [main/INFO] [EARLYDISPLAY/]: Trying GL version 4.6 18:34:54.303 game [18:34:54] [main/INFO] [EARLYDISPLAY/]: Requested GL version 4.6 got version 4.6 18:34:54.367 monitor Process Monitor Process crashed with exit code -1     screenshot of log: https://drive.google.com/file/d/1WdkH88H865XErvmIqAKjlg7yrmj8EYy7/view?usp=sharing
    • I am currently working on a big mod, but I'm having trouble with my tabs, I want to find a way to add tabs inside tabs, like how in mrcrayfishes furniture mod, his furniture tab has multiple other sub tabs to them, so i know it is possible but i just don't know how it is possible, any help would be appreciated, thanks
  • Topics

×
×
  • Create New...

Important Information

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