Bed Upgrade Mod

Here are the changes need to upgrade those mean beds to comfy ones so you don’t end up with a bunch of old beds laying around. It creates an action item when you click on the mean bed that, when clicked on, instantly “upgrades” (i.e. replaces) the mean bed with a comfy one.

This works (with the base alpha 5; haven’t test with post release).

This works (with the base alpha 5; haven’t test with post release), however there are a couple caveats that I would appreciate some help with. The first is that the rotation of the bed is not kept so the comfy one will default back to an unrotated position. The second in that the item information section (lower left of the screen, whatever that is called) will remain as if the mean bed was still selected. Just click on something else and everything is right with the world again, but just a heads up on what to expect.(now fixed, so no longer valid)

Here are the files that you will need to create in your mod.

manifest.json

{
  "info": {
    "name": The Update Bed Mod"
  },

  "mixintos": {
    "stonehearth/entities/furniture/not_much_of_a_bed/not_much_of_a_bed.json": [
        "file(mixintos/not_much_of_a_bed.json)"
      ]
  },

  "functions": {
    "upgrade_bed" : {
        "controller": "file(call_handlers/upgrade_bed_call_handler.lua)",
        "endpoint" : "server"
      },
    "select_new_bed" : {
        "controller": "file(call_handlers/upgrade_bed_call_handler.lua)",
        "endpoint" : "client"
      }
  }
}

mixintos/not_much_of_a_bed.json This is their internal name for the mean bed I guess.

{
  "components" : {
    "stonehearth:commands" : {
      "commands" : [
            "file(/data/commands/upgrade_bed)",
         ]
      }
   }
}

data/commands/upgrade_bed/upgrade_bed.json (note: make sure “myMod” below is replaced with the name of your mod).

{
   "type" : "command",

   "name": "upgrade_bed",
   "tooltip": "Upgrade a bed",
   "description": "Turns a straw bed into a comfy one!",
   "icon": "/stonehearth/entities/furniture/comfy_bed/comfy_bed.png",

   "action": "call",
   "function": "myMod:select_new_bed",
   "args": [
     "{{self}}"
    ]
}

call_handlers/upgrade_bed_call_handler.luac

-- (9/24/2014 - DrowsySloth) Code to upgrade a mean bed to a comfy one.
-- TODO: Validate that there are no bugs with this (i.e. works in a house, works when bed has an owner, etc).
-- To log use ex: radiant.log.error('server', radiant.entities.get_name(entity) .. ".facing=" .. facing)
local t = class()

function t:upgrade_bed(session, response, entity)
  -- Cache the location and rotation of the current bed before we destroy it, so that the new one matches it.
  local loc = radiant.entities.get_world_grid_location(entity)
  local facing = radiant.entities.get_facing(entity)

  -- Remove the mean bed.
  radiant.entities.destroy_entity(entity)

  -- Create the comfy bed in its place.
  local comfyBed = radiant.entities.create_entity('stonehearth:comfy_bed')
  radiant.terrain.place_entity(comfyBed, loc, {force_iconic=false})
  radiant.entities.turn_to(comfyBed, facing)

  return true
end

function t:select_new_bed(session, response, entity)
  -- Invoke the server-side method.
  _radiant.call('myMod:upgrade_bed', entity)

  -- Using nil here to essentially select nothing as there doesn't seem to be a
  -- deselect/clear method and I don't have a reference to the comfy bed entity.
  stonehearth.selection:select_entity(nil)

  return true
end

return t

Hopefully this helps folks.

3 Likes

hey there @drowsy_sloth … welcome aboard! :smile:

apologies if i’m being dense… but would you mind elaborating on what exactly this mod provides?

Does this tool manually rewrite/replace the old beds as new ones in the save file, or does it let you upgrade one to the other in-game? Because the latter would be a neat feature in vanilla.

It adds a command/button to the straw bed which will turn it immediately into a comfy one. Or rather, removes the old one and creates a new one at the same spot. Also, I don’tt hink rotation exists, it’s most likely an attribute of the mob component.

@RepeatPan is correct. Sorry for not being more clear on that.

Right now it is a free upgrade (mean it doesn’t cost you the same number of resources that building a comfy bed would), as there isn’t an existing upgrade pattern in the game that I know of, other than people of course. So, I’m not sure of the best method for charging for the upgrade (i.e. take a bolt of cloth) since the main pattern in the game if for an item to be created at the craftman’s bench not changed in place.

Seems like rotation would need to be stored somewhere on the entity for rendering purposes. However, what is it called, whether it is available in the lua object or some proxy/wrapper object I’m not sure. I assume lua has a way of listing out the attributes, so I will try to get time to look into that today.

edit: So looks like the entity is userdata, which means as a C type I’m not going to get much info from it. Installed inspect to at least dump out the metatable, but how to actually get that into a log file seems to be eluding me. Print seems to go to the void. They have radiant loggers, but not sure how to get those turned on. The search continues…

edit2: I have fixed the rotation in the code in the first post (post was updated). The new comfy bed will now rotate correctly to match the mean bed that was there before. I did notice in testing that the upgrade icon seems to be missing if you click on another mean bed. The action still works though, is just a display thing I need to figure out. Next on the list I guess.(fixed)

RepeatPan was correct about the mob component. That is essentially the code that entity’s get_facing method was using. I’m still not sure what the relationship is or why adding that component to the entity allows us to get the attribute from it, but it does work. A lot of the stoneheath modding seems like guess work to me at this point though.

I figured a hackish way to log just using radiant.log.error(‘server’, ‘something here to log’). Had to go with error level to get it to show in SH.log. Not pretty, but it works. Debugging the entity’s metatable was not useful though. Just standard object housekeeping methods and nothing specific to a game object. However, gave me a clue to look in the radiant.smod. Looking at entities.luac in modules gave me the methods to use on the entity. I just wish everything wasn’t obscured with variable names of n, e, and t everywhere. I can see how it speeds up performance, but is very frustrating to figure out.

edit3:Fixed the issue with the action command icon missing. I was using a load file that had a mean bed already created to save the time needed to get to that point. I had originally copied the comfy_bed.png file into a local folder rather than referencing it in the stonehearth smod when creating that save file. So apparently the save process includes a copy of the entity definitions and action commands. That still worked because even though my json file now referenced the png file in the stonehearth smod (which was wrong, missing a slash in the front) for that saved mean bed it was still going to the copy in my mod (which I hadn’t deleted). Weird.

Anyway, that is all I have to show for the last couple hours. Now looking into RepeatPan’s RP mods to see what I am doing wrong with the action bar (lower left of screen) not being updated. Do I need to restructure things to create and event to get it to work? I’m pretty stumped at the moment.

Sorry, about the long posts. Thought others going through this for the first time may find them useful. If they are more spamish please let me know and I will stop.

edit4: Last post of the night. Figured instead of trying to clear the selection I’ll just select the new entity. This call seems to be pretty common in the call handlers:

stonehearth.selection:select_entity(comfyBed)

However, I get an error about selection not being set (nil). Not sure where to go with this.

-- Script Error (lua) Begin ------------------------------- 
lua.code |    myMod/call_handlers/upgrade_bed_call_handler.luac:22: attempt to index field 'selection' (a nil value)
lua.code |    stack traceback:
lua.code |        [C]: in function '__index'
lua.code |        myMod/call_handlers/upgrade_bed_call_handler.luac:22: in function 
lua.code | -- Lua Error End
1 Like

Good work. :thumbsup:
I unfortunately can not help you with the remaining troubles.

Thanks. I got 30 minutes to play around with it some more and looking at classes like new_game_call_handler and place_item_call_handler that have both client and server methods I noticed the selection portion only existed in the client methods. So, the issue seems to be the context. Meaning that I am running this on the server side (as defined in the manifest for the function), when the selection is client side logic. stonehearth.selection only seems to exist on the client-side, which makes sense as that is more user specific, not server state.

So figured I could maybe run my method as client-side. That is big no, as things like get_facing don’t have their context then. So, I tried to split up the method call the first part as server side which does all of the replacement then invokes the selection method client-side. That was no go as the radiant.call only seems to work when invoked from the client-side. So, I flipped and had the client-side invoke the other method as server side, which kind of worked (no errors). Of course, that was moot anyway as i don’t have a reference to the new bed entity to select and there doesn’t seem to be a clear selection (deselect) method that I could find.

Anyway, here is the code I ended up with if anyone is interested. I guess the issue is now that I don’t have a way to deselect things, which is functionally the same problem I had before :frowning:

Relevant part from manifest

"functions": {
    "upgrade_bed" : {
        "controller": "file(call_handlers/upgrade_bed_call_handler.lua)",
        "endpoint" : "server"
      },
    "select_new_bed" : {
        "controller": "file(call_handlers/upgrade_bed_call_handler.lua)",
        "endpoint" : "client"
      }
  }

lua code

-- (9/24/2014 - DrowsySloth) Code to upgrade a mean bed to a comfy one.
-- TODO: Validate that there are no bugs with this (i.e. works in a house, works when bed has an owner, etc).
-- To log use ex: radiant.log.error('server', radiant.entities.get_name(entity) .. ".facing=" .. facing)
local t = class()

function t:upgrade_bed(session, response, entity)
  -- Cache the location and rotation of the current bed before we destroy it, so that the new one matches it.
  local loc = radiant.entities.get_world_grid_location(entity)
  local facing = radiant.entities.get_facing(entity)

  -- Remove the mean bed.
  radiant.entities.destroy_entity(entity)

  -- Create the comfy bed in its place.
  local comfyBed = radiant.entities.create_entity('stonehearth:comfy_bed')
  radiant.terrain.place_entity(comfyBed, loc, {force_iconic=false})
  radiant.entities.turn_to(comfyBed, facing)

  -- TODO: Need to clear the selection (lower left of screen) as it will remain the mean bed entry.
--  stonehearth.selection:select_entity(comfyBed)
--  _radiant.call('myMod:select_new_bed', comfyBed)

  return true
end

function t:select_new_bed(session, response, entity)
  -- Invoke the server-side method.
  _radiant.call('myMod:upgrade_bed', entity)

  -- FIXME: Using nil as there doesn't seem to be a deselect/clear method and I don't have a reference to the comfy bed entity.
  stonehearth.selection:select_entity(nil) -- Doesn't seem to do anything

  return true
end

return t

Edit: Never mind, I need some sleep. I forgot to update the action command to reference the new client-side method. It actually does deselect the mean bed now. Would be nice to select the new comfy bed, so I will have to work on that next. But the code above does work with the following change. Sorry about that.

Relevant part of upgrade_bed.json - Note the function name change

"action": "call",
   "function": "myMod:select_new_bed",
   "args": [
     "{{self}}"
    ]
2 Likes

gonna revive this thread

would like to see a mod that allows you to upgrade not only beds, but tables, chairs, dressers, and desks etc to the best quality that you have available or to a set quality defined by the user

also is there a way to upgrade a template so that when its placed it has the upgraded version of that item, but does not replace the template? this way it could include doors and windows
factorio has this as a mod but I don’t know if its possible in stonehearth

1 Like