Project Harmonia

90 readers
3 users here now

A work-in-progress life simulation game.

GitHub

founded 2 years ago
MODERATORS
1
 
 

Background

For those who don't know, I'm trying to create a FOSS life simulation game — something similar to The Sims.

I haven't posted updates in !projectharmonia@lemmy.ml about the project for a while, only updates to the related crates I maintain. It's just me and my wife didn't have enough motivation to work on it. Mainly because of the overwhelming amount of things we need to make - both assets and code.

Lifesims Are Hard

A life simulation game needs at least one customizable character mesh (which is a huge project on its own), a lot of clothes, animations, textures, and world objects. And coding it isn't easy either — it's basically like making 3 games:

  1. Life simulation.
  2. Building mode.
  3. Character creation. It's probably the smallest part, but still quite complex.

Plus, I'm using Bevy, which is a great engine but still quite immature. This means I have to implement many things myself, even basic features like UI widgets. Some of my work is available as standalone crates: bevy_replicon, bevy_replicon_renet and bevy_enhanced_input. On the bright side, people seem to like them — the input crate is even planned for upstreaming into Bevy. But this also takes time and distracts me from the game.

I guess that's why we don't have many life simulation games — they're quite hard to create even for big companies. For example, Life By You from Paradox got cancelled.

So, is it an impossible task for hobbyists? It would be a shame, because I recently asked which game people would most like to see a FOSS alternative for, and most people voted for The Sims.

A Different Approach

At first, I considered switching to creating a reimplementation that requires the original game assets, like OpenMW or OpenLara. But it's even harder to implement and for me it's not as fun as creating something from scratch. So I continued thinking.

When I created bevy_replicon, it originally used bevy_renet under the hood. But it’s not actively maintained, so after each Bevy release, I had to wait a while for it to be updated. Instead of switching to another messaging library, I decided to abstract the messaging layer completely and move the renet-specific logic into a separate crate called bevy_replicon_renet. I documented the API, and people started creating their own integrations. I decided to embrace this strategy by keeping the crate minimalistic but extensible. Now we have a small ecosystem of crates. I think it's great because more people are getting involved and I have less to maintain.

There also games like Garry's Mod and Luanti (formerly Minetest). They are basically empty by default and players just install mods that add mechanics, objects, story, etc., all made by the community.

All of this got me thinking: why not create a project like this, but in the life simulation genre? From the game menu, players could download character models, clothes, objects, scripts, etc., created by passionate modders. To avoid downloading each mod individually, I could provide mod lists for one‑click installation. This will significantly reduce the scope of the game. Also, I enjoy creating APIs: even when I lost motivation to work on the game itself, I still actively developed the crates. So developing a game like this should be similar.

I even came up with a name — SimGine, short for "simulation engine."

During development, I can test things on free assets wrapping them as mods. For example, I can use character meshes and clothes from the awesome MakeHuman. But this could be anything, even a loader for CCs originally made for The Sims games.

As for the game engine, I still think that Bevy is the right choice:

  • It uses ECS, which is perfect for parallel simulation of many entities.
  • It's incredebly flexible and modular, kinda in the spirit of the game.
  • It's just fun to use for me. When you making a game as a hobby - it's very important, otherwise I'll lose my motivation.

I mentioned that the engine is still immature, but we're getting there. The upcoming 0.17 release will feature hot reloading and finally adds built-in widgets. Plus, the crates I already made are close to feature-completion.

Project Plans

Right now, I'm planning to wait for the release of Bevy 0.17 and, in the meantime, add a few important features to bevy_replicon. After that, I think I'll start working on the game. I'll also start from scratch, since we'll need a different architecture — though I'll borrow some of the old code. And this time, I'll start from the character creator. It's a smaller part, and if I fail with the rest, at least we'll still have a cool app for creating digital avatars 😅

Not looking for any collaborators or mod developers yet — I need to create an MVP first. I expect this will take a quite some time. But I would like to hear your opinions about the idea in general.

2
 
 

An input manager for Bevy, inspired by Unreal Engine's Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

This update features a big rewrite into a component-based API. The core concepts remain the same, but are now expressed through ECS. It's recommended to revisit the quick start guide.

Showcase:

// Spawn a camera with an input context.
commands.spawn((
    Camera3d::default(),
    Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
    FlyCam,
    // Similar to `related!`, but you only specify the context type.
    // Actions are related to specific context since a single entity can have multiple contexts.
    actions!(FlyCam[
        (
            Action::<Move>::new(),
            // Conditions and modifiers as components.
            DeadZone::default(), // Apply non-uniform normalization that works for both digital and analog inputs, otherwise diagonal movement will be faster.
            SmoothNudge::default(), // Make movement smooth and independent of the framerate. To only make it framerate-independent, use `DeltaScale`.
            Scale::splat(0.3), // Additionally multiply by a constant to achieve the desired speed.
            // Bindings are entities related to actions.
            // An action can have multiple bindings and will respond to any of them.
            Bindings::spawn((
                // Bindings like WASD or sticks are very common,
                // so we provide built-in `SpawnableList`s to assign all keys/axes at once.
                Cardinal::wasd_keys(),
                Axial::left_stick()
            )),
        ),
        (
            Action::<Rotate>::new(),
            Bindings::spawn((
                // You can attach modifiers to individual bindings as well.
                Spawn((Binding::mouse_motion(), Scale::splat(0.1), Negate::all())),
                Axial::right_stick().with((Scale::splat(2.0), Negate::x())),
            )),
        ),
        // For bindings we also have a macro similar to `children!`.
        (Action::<CaptureCursor>::new(), bindings![MouseButton::Left]),
        (Action::<ReleaseCursor>::new(), bindings![KeyCode::Escape]),
    ]),
));

Advantages of the new API:

  • You can use Bevy scenes to describe bindings. When BSN lands, we'll get hot-reloadable actions for free. In UE, this is also expressed via Blueprints.
  • Everything is inspectable.
  • Modifiers and conditions are now accessible in systems, allowing you to adjust or read their data if needed.
  • Actions can be queried - especially convenient when using Single.
  • Things that didn't benefit from being static, such as prioritization and action settings, are now dynamic.
  • Things that were "inspired by Bevy," such as how bindings were defined, modifiers and presets, now actually utilize the Bevy API - meaning new users don't have to learn additional concepts.
  • The crate logic is much simpler.

Huge thanks to Alice for reviewing this monstrous +6,127 −5,738 PR!

📜Full changelog 📦bevy_enhanced_input

3
0
submitted 1 month ago* (last edited 1 month ago) by Shatur@lemmy.ml to c/projectharmonia@lemmy.ml
 
 

An input manager for Bevy, inspired by Unreal Engine's Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

Highlights

  • Pull-based API is now strongly typed, just like triggers. Example: actions.value::<Move>() returns the defined output type of Move.
  • Action mocking. Example: actions.mock::<Move>(ActionState::Fired, Vec2::ONE, Duration::from_secs(2)). The last parameter is generic, so you can also set the time in frames or until manually cleared.
  • Preparation for upcoming networking integrations. Mostly more convenient access to internals.
  • Many small but important ergonomic improvements.

📜Full changelog 📦bevy_enhanced_input

4
 
 

It’s a crate for server-authoritative networking. We use it for Project Harmonia, but it's general-purpose.

Probably one of the biggest releases. Here are some highlights:

  • Authorization system. By default, we verify protocol compatibility between client and server by comparing hashes. You can add custom data to the hash (such as the game version) or fully customize the logic using RepliconSharedPlugin::auth_method.
  • Static rules, such as Once or Periodic. Very fast to compute, useful for deterministic replication. We plan to add opt-in, more complex dynamic rules in the next release.
  • New syntax for constructing replication rules. It extends the old one and allows specialization of individual components when declaring groups.
  • Batched component insertion on replication. It's much faster, and all components are available in the user's observers.
  • DisconnectRequest event to request a disconnect after sending messages. Useful for sending things such as disconnect reasons.

📜Full changelog 📦bevy_replicon

5
 
 

It's an input manager for Bevy, inspired by Unreal Engine Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

A relatively small release with several ergonomic improvements, such as using BevyError instead of panic-based APIs, along with some bug fixes.

📜Full changelog 📦bevy_enhanced_input

6
 
 

It’s a crate for server-authoritative networking. We use it for Project Harmonia, but it's general-purpose.

Highlights:

  • Relationships networking. Use relationships to specify which entities should be replicated in a single message.
  • Immutable components support. Replication is automatically applied via insertion for them.
  • replicate_mapped now deprecated. Regular replicate now works for all components.
  • Support for no_std and environments without atomic CAS, such as thumbv6m.

📜Full changelog 📦bevy_replicon

7
 
 

It's an input manager for Bevy, inspired by Unreal Engine Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

This is a double release to make migrating to Bevy 0.16 easier for users:

  • v0.10.0 targets Bevy 0.15. It replaces the confusing GamepadStick preset with the much more flexible Axial preset, and introduces Clamp modifier.
  • v0.11.0 updates to Bevy 0.16 with no breaking changes. It adds support for no_std and per-context schedule configuration (useful for networking), which wasn't possible to implement in 0.15.

📜Full changelog 📦bevy_enhanced_input

8
 
 

Bevy 0.16 is around the corner with many exciting features!

I'm currently working on adding support for some of them in my networking crate, bevy_replicon.

I just finished implementing immutable component support.

Next up: relations! I outlined the idea in this comment. Hope I can get it implemented before the 0.16 release 🙂

As for my game, I'm considering making an interesting announcement about it soon.

9
 
 

It's an input manager for Bevy, inspired by Unreal Engine Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

This release contains many changes, most notably the component-based API for contexts. We've also reworked the documentation, now including a quick-start guide that walks you through the API. We would appreciate your feedback 🙂

📜Full changelog 📦bevy_enhanced_input

10
 
 

It's an input manager for Bevy, inspired by Unreal Engine Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

This release contains many changes, most notably the component-based API for contexts. We've also reworked the documentation, now including a quick-start guide that walks you through the API. We would appreciate your feedback 🙂

📜Full changelog 📦bevy_enhanced_input

11
1
submitted 4 months ago* (last edited 4 months ago) by Shatur@lemmy.ml to c/projectharmonia@lemmy.ml
 
 

It's an input manager crate for Bevy, inspired by Unreal Engine Enhanced Input. We use it for Project Harmonia, but it’s general-purpose.

I love our trigger-based API, but the push-style API needed improvement. Previously, users had to read values from a resource - unergonomic and a bit confusing.

Now, contexts are components! This makes our push-style API similar to LWIM while keeping all the trigger-based ergonomics 🙂

See more details in the PR.

I recently received blessing from Alice (author of LWIM) to upstream this crate as a future Bevy input abstraction. But first, we need to polish the API - it's much easier to iterate on while in a separate crate.

12
 
 

It’s a crate for server-authoritative networking. We use it for Project Harmonia, but it's general-purpose.

A small release with improvements to the messaging backends API and ergonomics. I wanted to draft these changes before Bevy 0.16 to simplify the migration.

I also drafted a new RC release that supports Bevy 0.16 with no_std support! Nothing is feature-gated, the crate now completely no_std. Aeronet's author is working on bringing no_std support to aeronet, so you should be able to use it together with Replicon for some unusual platforms soon 🙂

📜Full changelog 📦bevy_replicon

13
 
 

It's a crate for dynamic and contextual input mappings for Bevy, inspired by Unreal Engine Enhanced Input. We use it for Project Harmonia, but it's general-purpose.

After some brainstorming with Alice (the author of LWIM), I replaced trait-based context creation with triggers. It was quite a significant refactor, but defining reloadable bindings in observers is so convenient.

There are also other minor ergonomic improvements and bugfixes. See the changelog for more details.

📜Full changelog 📦bevy_enhanced_input

14
 
 

It’s a crate for server-authoritative networking. We use it for Project Harmonia, but it's general-purpose.

Notable changes

  • Connected clients are now represented as entities.
    • All related APIs are now component-based.
    • Entity is used to refer to a client everywhere, but ClientId is still present as a persistent identifier across reconnects.
    • Fast iteration and O(1) lookups.
    • Users can insert their own components or even replicate these entities.
    • Simplifies messaging backend integration.
  • Switch from bincode to postcard.
    • Better varint serialization to save bandwidth.
    • Opens the door for no_std support after the 0.16 release.

I also rewrote the quick start guide. My recent talk at Bevy Meetup #9 helped me with this. It now contains much more information, including details on how to write a messaging backend or implement client-side prediction. I also tried to make it as user-friendly as possible. Feedback about it is highly appreciated!

📜Full changelog 📦bevy_replicon

15
 
 

For the past few days, I've been working on the ultimate quick-start guide for bevy_replicon.

It now contains much more information, including details on how to write a messaging backend or implement client-side prediction. My talk at the last Bevy meetup helped me with this. Any feedback is appreciated 🙂

16
 
 

Previously, I used a special ClientId type to refer to connected clients and stored their data in several resources.

I wasn't satisfied with this API and decided to try turning them into entities. Now, Entity is the identifier, and components store related data. I'm quite happy with the results, but waiting for a review from the second maintainer: https://github.com/projectharmonia/bevy_replicon/pull/423

If you have any suggestions or ideas, feel free to comment 🙂

Just preparing the crate to the upcoming talk at Bevy Meetup #9. Still in a break from actual game development.

17
 
 

It's a virtual meetup about Bevy, and I will be one of the speakers!

My topic will be Networking in Bevy with ECS replication, where I'll talk about bevy_replicon and networking in general.

I'm currently focused on crates that I use in the game, just to take a small break from the project. But I hope to get back to it soon :)

18
1
submitted 6 months ago* (last edited 6 months ago) by Shatur@lemmy.ml to c/projectharmonia@lemmy.ml
 
 

It’s a crate for server-authoritative networking. We use it for Project Harmonia, but it's general-purpose.

Kinda our 30th anniversary 😅 This release introduces remote triggers. The API is similar to our networked events. Here’s a quick showcase for client triggers:

app.add_client_trigger::<DummyEvent>(ChannelKind::Ordered)
    .add_observer(receive_events)
    .add_systems(Update, send_events.run_if(client_connected));

fn send_events(mut commands: Commands) {
    commands.client_trigger(DummyEvent);
}

fn receive_events(trigger: Trigger<FromClient<DummyEvent>>) {
    info!("received event {:?} from {:?}", trigger.event, trigger.client_id);
}

Server triggers have a similar API. Targeting entities is also supported.

We now also provide an example backend and examples that directly from the bevy_replicon repo. The examples have also been re-written to take advantage of the latest Bevy and Replicon features.

📜Full changelog 📦bevy_replicon

19
 
 

Refined the bindings menu for my game and ported it into a standalone example for bevy_enhanced_input.

Alice (the author of LWIM) and I quite like the main concepts of the crate, and we’re planning to refine it further to create the ultimate input manager 🙂

20
1
Remote triggers (github.com)
submitted 6 months ago* (last edited 6 months ago) by Shatur@lemmy.ml to c/projectharmonia@lemmy.ml
 
 

Spend last week working on remote triggers for bevy_replicon.

Tried many approaches and finally satisfied with the implementation and public API.

Client triggers example:

app.add_client_trigger::<DummyEvent>(ChannelKind::Ordered)
    .add_observer(receive_events)
    .add_systems(Update, send_events.run_if(client_connected));

fn send_events(mut commands: Commands) {
    commands.client_trigger(DummyEvent);
}

fn receive_events(trigger: Trigger<FromClient<DummyEvent>>) {
    let FromClient { client_id, event } = trigger.event();
    info!("received event {event:?} from {client_id:?}");
}

Server triggers example:

app.add_server_trigger::<DummyEvent>(ChannelKind::Ordered)
    .add_observer(receive_events)
    .add_systems(Update, send_events.run_if(server_running));

fn send_events(mut commands: Commands) {
    commands.server_trigger(ToClients {
        mode: SendMode::Broadcast,
        event: DummyEvent,
    });
}

fn receive_events(trigger: Trigger<DummyEvent>) {
    info!("received event {:?} from server", trigger.event());
}

Observers are so nice, I use them in my game a lot and not having them networked was quite limiting.

After a review from second maintainer I will merge it and draft a new release 🙂

21
 
 

It's a crate for dynamic and contextual input mappings for Bevy, inspired by Unreal Engine Enhanced Input.

Actions now have a parameter that requires inputs to reset to zero before activation and continue consumption after context removal until they return to zero. This is very useful if you want to use the same input to toggle between contexts.

See the changelog for more details.

📜Full changelog 📦bevy_enhanced_input

22
1
submitted 6 months ago* (last edited 6 months ago) by Shatur@lemmy.ml to c/projectharmonia@lemmy.ml
 
 

It's a crate for dynamic and contextual input mappings for Bevy, inspired by Unreal Engine Enhanced Input.

It's a small release. I'm quite happy with the API, just wanted to make a few adjustments. Here are some highlights:

  • Replace SmoothDelta modifier with SmoothNudge. It uses StableInterpolate::smooth_nudge, which properly interpolates inputs across frames.
  • Remove InputContext::MODE. All contexts now work like InputContext::Exclusive (the default). If you want to share the same input across multiple entities, use a separate "controller" entity for a context and apply inputs to the desired entities. This approach is more efficient and explicit, so it's not worth having a special case in the crate for it.

See the changelog for more details.

📜Full changelog 📦bevy_enhanced_input

23
 
 

Getting it to compile wasn't too hard, thanks to the migration guide and deprecation warnings.

I took the time to rewrite my logic using new features like observers, fallible params, required components, picking, etc. The rewrite is massive: 98 files changed, 5197 insertions, 6303 deletions. And that's excluding Cargo.lock - it's all code.

I really like the changes. They made the code much clearer. Next, I plan some work on my crates.

24
1
submitted 7 months ago* (last edited 7 months ago) by Shatur@lemmy.ml to c/projectharmonia@lemmy.ml
 
 

Played with the lighting setup.

Switched from ACES to TonyMcMapface (Bevy's default). While ACES is very common, it forces a very specific aesthetic and makes everything look burned. TonyMcMapface is "boring", but it's good because it provides more control over the aesthetic.

I also tweaked the lighting color, adjusted the environment map intensity, and disabled bloom.

Here is the before and after.

before after

25
 
 

Over the last two weeks, I worked on walls. I needed precise placement for apartment building.

  • Added angle and length visualization.
  • Lengths and angles are now rounded (can be disabled by holding Alt).
  • Added ordinal angle snapping (can be enabled by holding Shift).
  • Simplified and optimized mesh generation.

I need a dashed gizmo style to make it look nicer. I opened an issue and it was implemented in less than 24 hours. Bevy development velocity is 🤯

view more: next ›