106 - Crafting UI Early Peek

February 14, 2021

Since the last journal entry I continued to make progress on the crafting interface.

I also started working on supporting undo and redo in the editor.

Crafting UI

Because the crafting UI is the first complex interface in the game, building it is requiring me to lay a good bit of UI foundation.

This passed week continued along that trend.

I introduced a UiComponent trait as well as a UiButton to make it easier to make buttons.

/// A component that can be converted into UIElement's to be pushed to a UserInterfaceResource.
pub trait UiComponent<UiId: Hash, N, I: KeyboardInputNormalizer<N>, TextAreaId> {
    /// Create UIElement's from this component and push them to the UserInterfaceResource.
    fn push_ui_elements(
        self,
        user_interface: &mut UserInterfaceResource<UiId, N, I, TextAreaId>,
        viewport_id: ViewportId,
    );
}

Over time I will continue to add more components.

I also made improvements to the GridLayout type to make certain layouts easier, such as laying out items in a row.

The crafting interface still needs textures as well as some positioning cleanup and functionality such as dragging and dropping ingredients in between ingredient slots. So there is more work to be done.

Interacting with the work in progress crafting interface.

Item Icon Generation

I started working on an asset compilation plugin that can generate icons for every item in the game.

I mentioned a need for this around a month and a half ago in 099.

Once this works every item in the game will have an icon.

This will make it much easier to know what ingredients you are attempting to use while crafting.

Editor Undo Redo

I spent some time early in the week thinking through the design of the editor's undo/redo system.

One interesting case that I needed to design for was undoing a brush stroke.

If a user is in terrain sculpting mode and clicks and drags their mouse, multiple edits are applied.

If they press undo they should go back to the moment before they first pressed down the mouse.

This meant that undo could not simply undo the last edit. It needed to be possible to go back to some state from multiple edits ago.

I ended up landing on a design where when we are pushing a new UndoDescriptor to the undo stack I use a match statement to determine whether or not to simply combine the new descriptor with the one at the top of the stack.

This allows me to have one big UndoDescriptor to be able to undo multiple terrain sculpting edits.

impl UndoRedo {
    /// Push an undo descriptor onto the undo stack.
    ///
    /// If the stack is full the item at the bottom of the stack will be removed.
    pub fn push_undo_desc(&mut self, undo_desc: UndoDesc) {
        if self.undo_stack.len() == UNDO_STACK_MAX_SIZE {
            self.undo_stack.remove(0);
        }

        if let Some(stack_top) = self.undo_stack.last_mut() {
            match (stack_top, undo_desc) {
                (
                    UndoDesc::TerrainDisplacement(stack_top),
                    UndoDesc::TerrainDisplacement(incoming),
                ) if stack_top.stroke_id() == incoming.stroke_id() => {
                    stack_top.combine_with(incoming);
                }
                (_, undo_desc) => {
                    self.undo_stack.push(undo_desc);
                }
            };
        } else {
            self.undo_stack.push(undo_desc);
        }
    }
}

I still need to create UndoDescriptor's for all of the existing edit operations that were created before I introduced' undo/redo. I plan to take care of that this week.

Other Notes / Progress

  • Canceled my Adobe Illustrator subscription since I have not touched it in months. Had to pay a $41 cancellation fee.

  • Planning to start using a g3 4x large EC2 instance for CI jobs since once I have the item icon generation working I will need access to a GPU when compiling assets. At over $1/hr a g3 4x large is too expensive for me to leave running at all times, so I will start it up whenever I need to run CI and set up a CloudWatch alarm to have it shutdown whenever it has been idle for 15 minutes.

Next Journal Entry

My focus this week will be getting the item icon generation asset compilation plugin working.

After that I will set up a self hosted GitHub actions runner on an EC2 instance that has a GPU. I'm expecting to fiddle a bit with installing Vulkan drivers.

If I get all of that working this week I will get started on implementing drag and dropping items into crafting ingredient slots.


I will be back next week. Goodbye for now.

- CFN