Skip to content

Add music track registry and biome mood - #3679

Merged
IntegratedQuantum merged 4 commits into
PixelGuys:masterfrom
yel0h:music-data-model
Oct 7, 2026
Merged

IntegratedQuantum merged 4 commits into
PixelGuys:masterfrom
yel0h:music-data-model

Conversation

@yel0h

@yel0h yel0h commented Oct 4, 2026 •

Copy link
Copy Markdown
Contributor

Progress toward tag-based music selection as outlined in #732. This PR is just the data model and changes no behavior.

Each zig.zon file in the music folder declares tags, a mood target, a tolerance and a chance for the song of the same id. Adds Mood, a point in anxiety/energy/sanity space. Biomes and tracks are positioned in this space. Biomes can now declare a baseMood. Cave biomes default to a higher baseline anxiety.

Example music track file:

.{
    .tags = .{ .peaceful, .day, .surface },
    .moodTarget = .{.anxiety = 0.2, .energy = 0.3, .sanity = 0.8},
    .moodTolerance = 0.6,
    .chance = 1.0,
}

@Wunka

Wunka commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

I think an artist opinion would be nice here @ikabod-kee @careeoki

@ikabod-kee

Copy link
Copy Markdown
Collaborator

Oh holy shit. Let me check this out

@ikabod-kee

Copy link
Copy Markdown
Collaborator

This looks very good to me! I'm not sure if Quantum actually wanted the mood system like that so he'll have to give you some feedback on this- but this is a very good start and I'm excited to see some implementation.

@IntegratedQuantum IntegratedQuantum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of just adding these values, please also outline how you intend the system to work, also check out some criteria I added in #732 (comment)

Comment thread src/assets.zig Outdated
addon.readAllZon(allocator, "items", true, &self.items, &self.itemMigrations);
addon.readAllZon(allocator, "tools", true, &self.proceduralItems, null);
addon.readAllZon(allocator, "structure_tables", false, &self.structureTables, null);
addon.readAllZon(allocator, "music_tracks", true, &self.musicTracks, null);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the metadata should be put in the same folder, like we did for models.

Comment thread src/main.zig Outdated
pub const migrations = @import("migrations.zig");
pub const models = @import("models.zig");
pub const mood = @import("mood.zig");
pub const musicTracks = @import("musicTracks.zig");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please don't make a new root-level files for this. This clearly is only used for music, thus belongs in the audio file and folder.

Comment thread src/mood.zig Outdated
@@ -0,0 +1,12 @@
pub const Mood = struct {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also be declared locally in the MusicTrack struct

Comment thread src/audio/music_tracks.zig
Comment thread src/musicTracks.zig Outdated
}

pub fn registerTracks(tracksZon: *Assets.ZonHashMap) void {
anyTag = Tag.find("any");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For any comptime-known tags, just declare them in the Tag enum

Comment thread src/server/terrain/biomes.zig Outdated
subBiomeTotalChance: f32 = 0,
preferredMusic: []const u8, // TODO: Support multiple possibilities that are chosen based on time and danger.
baseMood: main.mood.Mood,
musicTags: []const Tag.WeightedTag,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My idea was to have tags be hard restrictions. If we add weights to them I think the resulting vector space may get too big to be able to produce good matches on the mood and the tags (e.g. a few tags on a track that doesn't match the mood at all may outcompete any tracks that do match the mood and vice versa).

Also tags should not be specialized, to allow one system (e.g. music) to make use of the tags of another system (e.g. .oak).

@yel0h

yel0h commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

The way I wanted this to work was:
The player has the 3-value mood, which is affected, for example, by actions described here. The mood values always decay toward the current biome's baseMood.
A music track is a candidate to be played if there's at least one match between its tags and the biome's musicTags.
Each candidate then has a weight calculated based on:

  • the sum of the matching tags' weights,
  • how well the mood fits, considering its distance to the player's mood, and the moodTolerance value,
  • the track's weight specified in the zon.

When the current song finishes playing, the system does a weighted random pick of the next track, excluding the last few played unless that would leave no candidates. If the player travels to another biome whose tags don't match the current song, it immediately fades to a new one.
And if there are no candidates to choose from, it just picks among tracks tagged .any.
So basically I just put the ideas from #732 together.

@yel0h

yel0h commented Oct 6, 2026

Copy link
Copy Markdown
Contributor Author

Now I guess if we want hard filtering tags, that would mean that for a track to be considered a candidate, all of its tags have to be among the current biome's tags. In that case, the .any tag is also not needed, it's enough to leave a music track untagged. The candidate weight calculation would then depend on the track's weight and mood fit only.

@IntegratedQuantum IntegratedQuantum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add at least one example to a biome, and make a PR with an example music track to Cubyz-Assets (note that you'll also need to touch the release CI script to copy the file over)

Thanks for working on this by the way, this is quite important, and something I've been neglecting for quite a few release cycles.

Comment thread src/audio/music_tracks.zig Outdated
Comment thread src/server/terrain/biomes.zig Outdated
Comment thread src/audio/music_tracks.zig Outdated
Comment thread src/audio/music_tracks.zig Outdated
Comment thread src/audio/music_tracks.zig Outdated
Comment thread src/audio/music_tracks.zig Outdated
Comment thread src/audio/music_tracks.zig Outdated
@yel0h yel0h changed the title Add music track registry and biome mood/music tags Add music track registry and biome mood Oct 7, 2026

@IntegratedQuantum IntegratedQuantum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one more thing

Comment thread src/audio/music_tracks.zig Outdated
energy: f32,
sanity: f32,

pub fn loadFromZon(zon: ZonElement, isCave: ?bool) Mood {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bools in functions signatures are hard to read.

Suggested change
pub fn loadFromZon(zon: ZonElement, isCave: ?bool) Mood {
pub fn loadFromZon(zon: ZonElement, options: struct{isCave: bool = false}) Mood {

@yel0h

yel0h commented Oct 7, 2026

Copy link
Copy Markdown
Contributor Author

Replaced

@IntegratedQuantum IntegratedQuantum left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't wait to see how this turns out.

@IntegratedQuantum
IntegratedQuantum merged commit f1e494a into PixelGuys:master Oct 7, 2026
3 checks passed
@yel0h
yel0h deleted the music-data-model branch October 7, 2026 19:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants