[Seeking help] Choosing model variant before placement

Some modular decorations would require a bunch of separate entities just for the sake of changing the model. I’d like to have one entity instead and choose the model before placing. There’s stonehearth:customization component which allows changing predefined styles, which may be colour palettes or model variants. Expected result is:

  • model variants are stored as customization styles,
  • while placing an item pressing slash ( / ) increments style index so the model changes,
  • in item movement mode: starting style is the style of root entity,
  • in building mode: if an entity being placed is of the same type as the last one, start from the style of the last entity, not from the default.

If you have any ideas how to do that please post here. Right now I have no idea how to communicate between root, ghost an cursor entities so style change is applied to all of them.

Original post

I wanted to add new functionality to item placement so in addition to rotating (default: comma and dot) it would be possible to toggle between model variants listed in a separate pawel_API:model_variants component. I’ve already figured out how to add a new hotkey and mapped build:toggle_model to so-far-unused slash key.

Files I think may be involved are:

  • services/client/selection/entity_or_location_selector.lua: at least _on_keyboard_event() must be modified to add reaction to the new hotkey, also a function to switch to the next model from the list is needed;
  • services/client/build_editor/item_placer.lua: prepares everything for placement so reading the model variant of existing entity seems a minimum to add here.

The thing is I’m not sure how should the data from cursor entity be passed to render_info component of the new entity.

1 Like

Have you looked at Stonehearth_Client.js:_placeItemOrItemType() function yet? That seems closer to the code where the item actually gets placed.

Keep me updated on what you figure out, this is relevant to some modding I’m doing :slight_smile:

Yes, I’ve already examined it. It codes UI responses which are irrelevant as I need to apply changes to entities.

Okay, and you’re aware of the “model_variants” component and how that interacts with “customiztion_component”? Customization component has :change_customization(subcategory, style) which you can define MODEL as the subcategory.

Or, still using model_variants component, you can imitate what happens in renewable_resource_component:

function RenewableResourceNodeComponent:_reset_model()
   local render_info = self._entity:add_component('render_info')
   render_info:set_model_variant('')

   if self._renew_effect then
       self._renew_effect:set_finished_cb(nil)
                    :set_trigger_cb(nil)
                    :stop()
       self._renew_effect = nil
   end
end

From this, I would assume you simply mixin new model paths to the entity’s json, then define that in calling render_info:model_variant(’…")

I knew about customization_component but I did not consider using it for non-Hearthling purposes. May make matters simpler but it won’t allow changing hitboxes and that’s why I was thinking about new component instead. As a trade-off I could separate colour and shape changes and assign them to different keys. That being written, I think extending the functionality of model styles to include separate hitboxes and model origins seems the most powerful and not so hard to implement (no new saved variables involved so it would work).

The problem is I have to modify item placement code so style changes are applied to three entities: cursor, ghost and main entity with cursor being created only on the client side and ghost/main on the server side. I wasn’t aware of the problem unless I studied rotation management code.

Don’t reinvent the wheel, Im sure there is are simple methods using the existing components, maybe check out:

I need to change at least animation_table and effect_list together with model variant because this is intended for Archmod roof tiles which use rotated rectangles. Technically, there is an alternative to that: one huge animation for all tile variants and careful naming of model parts in .qb files. But I still need to change the model and every time I want to swap odd and even sized models I’d need to change model origin.

For fence variants I’d also need to add and remove hitboxes. For region collision shape and model origin debug tools code is quite useful, not sure how to implement the rest.

EDIT: I think I’ll have to surrender because reverse engineering led me to entity forms lib Lua which I won’t touch no matter what, it is too important. Switching between different entities sharing an iconic form could be easier, but creates different issues so changing model variant via stonehearth:customization seems the only reasonable way to go.

I wish I could help :slightly_frowning_face: but I’m now lost what exactly you’re trying to achieve. Don’t you simply want to be able to cycle through model forms like how you rotate an object while placing it?

1 Like

Also, I’d recommend not worrying about fences, the devs keep saying those are gonna get an overhaul, so they possibly won’t even exist as individual entities down the line.

Yes, that’s exactly what I want and if I drop fences then toggling model variant is enough.

Ooooo have you looked at the mob component yet? I just discovered it. It also stores info about the models root, position, ect. What’s more, take a look at these functions off entities.lua:

  function entities.move_to(entity, location)
     radiant.check.is_entity(entity)

     if type(location) == "table" then
        location = Point3(location.x, location.y, location.z)
     end
     entity:add_component('mob'):move_to(location)
  end

  function entities.move_to_grid_aligned(entity, location)
     radiant.check.is_entity(entity)

     if type(location) == "table" then
        location = Point3(location.x, location.y, location.z)
     end
     entity:add_component('mob'):move_to_grid_aligned(location)
  end

  function entities.turn_to(entity, degrees)
     if not entity or not entity:is_valid() then
        return
     end
     radiant.check.is_number(degrees)

     entity:add_component('mob'):turn_to(degrees)
  end

  function entities.turn_to_face(entity, target, opt_no_interpolate)
     local point = entities.get_facing_point(entity, target)

     local no_interpolate = not not opt_no_interpolate

     if no_interpolate then
        entity:get_component('mob'):set_skip_interpolation(true)
     end
     if point then
        entity:get_component('mob'):turn_to_face_point(point)
     end
  end

Now I can’t find info on what other methods pertain to the mob component but it warrants some testing!

From messing with the entity editor in debug tools (which shows you the mob component’s info), it appears modifying the mob component is your way to go about updating the model’s region shape and origin. Then, model_variants would be how you change the actual qb file. Im still testing however.

I know what I need to do, the problem is there are 3 entities involved in placement process: client-only cursor entity which spawns a ghost entity server-side when clicked and root entity replaces the ghost entity when it is placed in the world. What’s even more complicated is placing objects in building mode when a different function is used because items are placed from recipe catalogue instead of inventory (root entities don’t even exist prior to placement). I don’t know how to get beyond cursor entity because even if I apply changes to it they have to be transferred to ghost entity and then to root entity. Examine how rotation data is transferred between entity forms, it involves many different classes (searching for ‘rotation’ in stonehearth.smod returns 279 matches in 40 files).

Out of curiosity, did you get anywhere with this? I’ve just created some modular decorations and decided that at my level it would be a leap too far to make the changes you’re talking about so I’ve just added 5 different entities for the different configurations.

There’s some functionality in ACE that could be used to this end, but it’s not fully developed for it currently (we’re currently using it for kingdom-dependent model variants, but it’s built to allow specific, random, or progressive model variant changes).