This Week In Veloren 91

8 minute read26 October 2020

Authored by AngelOnFira

This week, we have lots of writeups. @Sam talks to us about the buff system. @Adam is working on designing an improved alignment system to improve hostility calculations between entities. @xMAC94x wrote about the CI issues we've been having for the past few months, and what has been done to resolve them.

- AngelOnFira, TWiV Editor

Contributor Work

Thanks to this week's contributors, @xMAC94x, @Sam, @Bbenton91, @imbris, @Adam, @Capucho, @AngelOnFira, and @zesterer!

This week, @James has been working on a way for SFX to be mapped to blocks. This will be used for ambient sounds like crickets, birds, etc. This system is still in the works. @LunarEclipse has been working on updating information about Veloren on the IGDB, which Twitch uses to categorize its games.

@Pfau created 2 new sets of armour, finished the buffs UI, and added the first underwater sprites. This week he'll create box art for Twitch, draw some ring concepts, and add more underwater sprites. @Sam has been doing a lot of work on the buff system. @Gemu finished up some sword models, and is working on a few new animal models to improve biome diversity.

Buffs by @Sam

Hey, @Sam here. Recently I've been working on player buffs. Buffs are separated into several components:

  • kind: the main identifier of what a buff is. It is used to construct what effects the buff has. Kinds could include bleeding, enflamed, crippled, and stunned.
  • data: contains data common to all buffs. Currently consists of the buff strength and the buff duration, but may expand later to include other fields.
  • effects: what effects the buff has. The currently implemented effects are a health change over time (so this covers both damage and healing), and changing max health.
  • time remaining: time remaining on the buff. It is different from the duration stored in data though because the duration in data is static and references the initial duration.
  • categories: a list of descriptors to the buff, such as physical, heat, environmental, etc. They don’t currently have a use, but will be used later when spells and other abilities are added that may have effects such as: immune to all heat-related debuffs, or something similar.
  • source: what applied the buff. If it’s a player, this can be used to award XP if something dies due to damage over time effect.

Buffs will not stack, but instead the strongest buff of each kind will apply its effects, and the other buffs of that kind remain "inactive". While inactive, they still tick down their duration, and will replace the stronger one if it decays before the weaker one.

Note that the stacking of buffs applies to buff kinds and not buff effects, so for example, you can be under multiple damage over time effects, such as bleeding, enflamed, and poisoned, you just cannot be under the effects of multiple bleeding debuffs.

The branch that added buffs was primarily focused on getting a buff system into the game. Now that it has merged you won’t notice to much difference yet. Currently, the only buff you will encounter for now is a bleeding debuff, which has a 10% chance to be inflicted by melee attacks. However, more buffs are on the way. Specifically, food is being reworked to provide a regenerative buff instead of an instant health restoration.

Alignment and Hostility by @Adam

This week I began looking into how we could refactor the alignment system to support more complex scenarios. I haven't any solution in place yet, but I'm going to provide a bit of background on the problem itself.

Current State

The alignment system as we have it is just a simple enum:

pub enum Alignment {
    /// Wild animals and gentle giants
    Wild,
    /// Dungeon cultists and bandits
    Enemy,
    /// Friendly folk in villages
    Npc,
    /// Farm animals and pets of villagers
    Tame,
    /// Pets you've tamed with a collar
    Owned(Uid),
    /// Passive objects like training dummies
    Passive,
}

However, this is too restrictive, even for simple ownership. Imagine something is Owned: despite having the Uid of the owner, we don't have the information about who that owner is hostile to. If we wanted to have owned entities to divert to the owner's hostility, then we would then need to pass possible owners' hostility information for both entities when we wanted to check hostility. And then what happens if those owners are also owned? You can start to see that this current implementation needs to be more robust. From here I will outline what the system needs to be able to do.

System Requirements

  1. System needs to support dynamic Settlement hostility. A world may have any number of settlements, but an aligned entity may only be aligned to one settlement at a time.
  2. System needs to support racial hostility. An aligned entity always has a race. Races have varying hostility toward other races.
  3. System needs to support individual hostility. An aligned entity may have overrides for specific other entities. For instance, if a neutral NPC is hit by a player entity, that NPC should be able to become hostile to that player entity.
  4. System needs to support ownership. An aligned entity may be owned by another entity. If an entity is owned, it may or may not want to divert to the owner's hostility.
  5. A reputation system may or may not be implemented. If it is, this system need to be able to incorporate that.

Analysis

An additional requirement that I want to achieve is a single lookup between entity Uids, something like:

hostility.is_hostile_to(Uid)

So we do not need to pass in the other information that an entity may or may not have, such as Ownership or Settlement data whenever we want to check hostility.

Looking forward, we will likely have many components (i.e. Race, Settlement, Ownership) that will affect one entity's hostility to another. Because we don't want to require hostility checks to ask for all these different components, how do we manage all these memberships when these components are updated?

So really, this problem boils down to two challenges:

  1. How do we effectively manage the hostility of an entity given the various sources of that determine it, without requiring developers to remember to update hostility any time they update those other sources?
  2. How do we keep the hostility check call as simple as possible? Ideally entity_a_hostility.is_hostile_to(entity_b)

In the next few weeks, hopefully we can find some resolution to these questions!

Fixing CI by @xMAC94x

Two months ago we broke our CI. This included documentation generation and code coverage. We lost information on how our test coverage was doing and our documentation was frozen. Fixing it required some fiddling with various public crates and some communication with external maintainers. We even found a bug in Rust itself while doing so.

Long story short, we needed to switch our Docker CI image from debian9 to Ubuntu 18.04 as the git lfs package was causing problems on Debian, and newer versions require a higher glibc version. We had to upgrade the Rust toolchain as this fixed a problem in macro handling which caused a big in the documentation cargo doc.

To fix tarpaulin we had to fix multiple errors. First of all, wayland-client 0.23 was causing problems so we had to update this to 0.27. However, we depend on some crates which have not done this update, so we did it ourselves. As glutin, winit, and conrod are quite dependant on each other. packed_simd also had a problem that was fixed. The RustC compilation problem we found isn't yet fixed, so I introduced a workaround in our affected vek code.

All in all, many things broke - I hope we can simplify our custom clone repos in the future: winit, vek, gfx-rs, rusttype, and conrod can hopefully all be replaced with iced. Now our CI is faster, down from 55 mins to 35 for a full run. I will look at it further after I do some performance fixes for Veloren 🙂

The mountains to explore. See you next week!