Mini Machines Mod

by Kryzeth

Miniature versions of assemblers, electric furnaces, etc. Full integration with all of Bobs mods and ShinyBobGFX/ShinyAngelGFX, Industrial Revolution, Factorio Extended Plus (FXP), Gotlag's Electric Furnaces, AAI Industry, Fantario, and One More Tier. (independently, not necessarily simultaneously)

Content
2 days ago
0.13 - 2.0
12.0K
Manufacturing

b [Pending] Future-proofing your scaling methods

4 years ago
(updated 4 years ago)

The way you currently copy from source prototype definitions is insufficiently dynamic and makes two key assumptions that cause incompatibilities when e.g. Bob's Assembly changes its Chemical Plant graphics (aka this is an issue now).

The assumptions that I noticed, looking through the code:
1. You assume a static number of layers, whether that's 1 or 2, presumably the number of layers that existed when you added support for a given mod/entity.
2. You use the width/height values of the source prototype at the time you added the code, rather than copying it.

I'd suggest redoing your scaling function, or adding a function, so that you can transcribe entire tables agnostic of what fields are or aren't present, and without assuming what the values are, and then scale the result. This would protect you from startup blockages related to dependent mods changing images/sizes/prototype definitions.

This would presumably also let you scale entities regardless of which mods are or aren't present, since the only static value would be an entity name (and some level of assumption about the main definition being defined, i.e. whether it's a picture or animation).

Tbh, there's probably a way to check what tables are defined on an entity and then if those tables are present, copy, scale, and make the mini version. At which point you're wholly future proof and the only vulnerability is if the entity name changes for some reason (like when green-transport-belt became ultimate-transport-belt...).

Or actually you don't even NEED to check, since if it's nil, it will remain nil. So you just need a superfunction specifically designed to loop through a Prototype definition and copy the relevant tables to your new mini entity, and scale the relevant fields, and this could be entity-type agnostic, I expect.

4 years ago
(updated 4 years ago)

Depending on the entity in question, the functions already in place don't make any assumptions, and just make an attempt to resize anything that might be there.

Specifically, "reduce(entity)" applies to the graphics of the various entities of the game, and there are dozens of small checks for fields like animation, animations, animation_shadow, working_visualizations, circuit_connector_sprites, etc etc.

Most entities in vanilla are simple, and only have a scale, shift, and hr_version.scale and hr_version.shift to change, and the checks apply a simple 2/3 reduction to the size of those graphics, and then shift the graphics by 2/3 to line up properly on the terrain. Even the graphics with layers can only have a specific number of layers, and the function should check how many layers are present, and apply the same 2/3 scale and 2/3 shift to each.

But for some reason, the chemical plant graphics (and I think a couple others) use unique functions to generate their graphics, and even when iterating through each layer and individually applying a 2/3 scale and 2/3 shift, the graphic would be incorrectly placed, or the changes just wouldn't apply (or worse, the game would throw an error on load)

So for chemical plants specifically, I took the easy route and just copied the entire animation field as it existed in the base game, and performed a 2/3 scale and 2/3 shift inside that function, overwriting what existed, and properly shrinking down the graphics. Then I did the same for bobs, when they updated to use the same unique function.

Iirc, the problem specifically was the value generated by util.by_pixel, which is how the shift is calculated for chemical plants. Something about that function just wouldn't scale properly afterwards; only when it is first declared.

For most other entities though, the code should be dynamic enough to not break when other mods update their graphics or values. Unless you can locate any specific problem areas? Like, line by line?

4 years ago

Ah, nice. Forgive me, I only looked closely at the Chemical Plant. ;D

4 years ago

Understandable, considering it totally falls under the "not future-proofed" and being "insufficiently dynamic" and is 100% the reason for the current errors. Better get to work on that about now, but thanks for the suggestion!

4 years ago

It's partly my fault your mod broke, cause I gave Bob new graphics. I love Mini Machines and had it enabled while I was making my wip Reskin mod... and it just wasn't playing nice. :c

4 years ago

Lol don't worry about it. It's may be a very easily broken function, but also about as easy to fix, once I look into the meat of things. I'm excited to see what you've made! ...once I can get the game to load up again lol. The old chemical plant recolors always seemed a little off to me.

4 years ago

I gave him new-new graphics that he hasn't put in yet, but he has the intermediate set which are... mostly fine.

Preview (with custom colors turned on, atm, since testing the various masks)
https://i.imgur.com/2dKyAza.jpg

4 years ago
(updated 4 years ago)

Woaah, that is looking sleek. So does that mean you're allowing the user to change the color progression for each set of machines? Dayumm

Also uploaded a fixed version, v7.0.3. I realized the real issue after some testing. I can totally make bobs chemical plants entirely dynamically, since he doesn't use the "make_4way_animation_from_spritesheet" function that vanilla does. Which should hopefully solve that issue for good; but still don't know why vanilla doesn't work.

Copying the entire definition, including the "make_4way_animation_from_spritesheet" function, and shrinking the scale and shift values by 2/3 works perfectly as expected, but trying to iterate a 2/3 shrink to the values afterwards, causes the shadow to be off-center, and I have no idea why.

4 years ago

You could probably look at the util.shift function and undo the conversion it does, then apply the shift. That's something I'd try.

4 years ago
(updated 4 years ago)

Though, idk. I turned Mini Machines back on and here's the results without me doing anything:

Chemical Plants:
https://i.imgur.com/19dZCur.png
Edit: I see why Chemical plants are fine, Bob's has 3 layers, I have 4, the last layer is Shadow, so the highlights got scaled properly but Shadow didn't.

I use make_4way... to do those graphics but it read and scaled them right, so idk? xD

But Mining Drills/Storage Tanks seems to assume only 2 layers? It missed the highlights layer:
https://i.imgur.com/LKGQ83k.png
https://i.imgur.com/rjtzxVA.png

And it doesn't seem to pull pipe pictures from the source entity? Idk:
https://i.imgur.com/qkjTtd3.png

And icon_size is assumed instead of copied, I'm guessing?
https://i.imgur.com/nwLxFFf.png
https://i.imgur.com/QlTIZbj.png

Anyways, you don't have to do anything about this, my mod isn't even out, lol. But these were things I noticed just as-is.

4 years ago

Hmmm... interesting. There may be more hardcoded entries than I had originally assumed. But no no, these are definitely issues and I would want to fix them, just in case! Future proofing indeed!

But yeah, the mining drills and storage tanks are straight wrong; need to fix.

The pipe covers pictures.. they're mostly placeholder? I remember having issues with placing those or something... I know shrinking the pipe covers is out of the question, since I would like them to visually match the size of externally connected pipe; but their placement had to be modified still. I'll look into them.

Icon size... that's another thing to look into. Those issues might be carry-overs from before icon/icons became more complex and dynamic. I've had to fix them for one of my other mods, but I don't think I applied the fix to this one (or at least not properly)

4 years ago

At least where pipe covers are concerned, I'd probably support those directly since I'd make ones that work better when on small machines. You can probably just copy the fluid box straight, and then just modify the fields for where to place them, since those don't scale.

4 years ago
(updated 4 years ago)

Okay, I think I have fixed mining drills and storage tanks, that was simple enough.

For the icons, while I do assume the icon size, I actually define a personal set of icons to use depending on what mods are loaded. The problem here is that you have (presumably) defined the icons field, instead of just icon (probably for the color masking?). Since my mod normally only uses the icon field, any mod that used the icons field would take priority over mine.

And of course, the only other mod that did so, was ShinyBobGFX (or ShinyIcons, probably that one actually), and that was specifically for the tiered bars that ran along the side. I probably should just overwrite the icons field anyways. It shouldn't make much of a difference for the most part. Though there was a function in the Factorio Standard Library mod that I use, which had a specific ReplaceIcon function, so I could replace both icon and icon_size in one short line; but ah well.

And lastly, the pipe covers; I think I did them manually because I couldn't figure out how to change the input and output positions when I first made this mod. But yeah, an exceedingly simple fix, since I already knew where the ports should be; just had to change a single value for each machine. They look weird, as usual, but shouldn't overwrite anything else about the graphic.

I'll upload what I have, even though it probably won't be useful to anyone else.

....oh, and the chemical plant.. still have to figure that one out....

4 years ago
(updated 4 years ago)

Awesome!

I'll probably just have mini-machines as a dependency and just go through and handle those icons myself, since I plan to do something weird, and plan to do custom pipe-pictures for the reduced machines. (Though if the goal is mod compatibility perhaps I should try and let you solve it?)

Posila pointed out that item definitions can have a pictures field (so that in-world sprites different from in-GUI sprites), specifically he pointed out how iron-ore is defined, but this would let me do bars in the GUI and not in the world. So don't worry so much about my icons. :D

Edit: To add, the current way that I do icons is I feed my icon definition to an assign function, which will either erase the icon field or the icons field, depending on which one we're using, so that only one field is left. Maybe this is bad form. Hm.

Also, you appear to have some stray code that does something to Assembling-Machine-6's icon?
https://i.imgur.com/d9dAHgp.png

4 years ago
(updated 4 years ago)

Hmmm, you might have to make that a separate mod from bobs, I think... since I might have a dependency to them already. And probably the worst thing that I do is run most of my code during final-fixes (but it's for a good reason!)

It would be incredible if you could make them look "pretty" somehow. The recipe and pipe icons usually cover them for the most part, but for anyone who has that disabled (or hits Alt for any reason), they look so bad lol.

Hmmm, sounds interesting! That probably isn't too bad. Sounds like forcing your icon/icons to be the primary icon, regardless of whatever else might have been previously defined. If you're trying to replace the existing icon/icons, then that's probably the most best way to do it.

4 years ago

If I have to do a separate mod just for mini machines that's not an issue, lol.

4 years ago
(updated 4 years ago)

Just saw your latest edit on previous post, but yeah, there was something.. off about bob's assembling machine 6 icon that I just didn't like. I think it either had the same amount of gears as assembler 5, or the gears were off or something weird when I did my manual reduction of the icon for the mini assembler 6; I forget what the issue was.

So I made a new sprite to override it when playing with bobs (which is proobably bad form, but nobody else has noticed it yet, so..). It probably sets the icon_size to 32 (which is the size of my replacer icon) and it either loads after your mod, or isn't overwritten by your mod.

4 years ago

I don't want to make a hackish fix to fix your hackish fix. Q_Q

4 years ago

Just complain to Bob, if it's still bad, he'll fix it. :D

4 years ago

OH I remember the issue lmao. There are ZERO gears on the assembling machine 6 icon. It's literally just a shrunken down copy of the entity itself.. it looks terrible compared to the others.

I know that adding a 6th gear in the intended location wouldn't be visible in the crafting menu (covered by a number), so it wouldn't make sense to add it there. My edit has the 6th gear right at the center of the icon, stacked on top of the other gears, so it's not perfect either.

I don't think bob cares all that much (considering it hasn't been changed since like, Factorio 0.13 or 0.14, maybe even earlier than that? And other mods like ShinyIcons exist to redo all of the icons anyways, so I know it's not a priority...

If you already have as a separate mod, and it probably will have an optional dependency to mine, you can just re-set the icon_size? I think you should be doing that already, in case of any other mods replacing the icons...

4 years ago

I explicitly set icon_size in my definitions, are you? :D...

4 years ago
(updated 4 years ago)

I have it setup so it's not a dependency, at the moment, which lets me Reskin bobs in data-updates, and then you come along and make your mini-machines using the reskinned structures.

If I set you as a dependency, I'm not sure what it'll do. Currently I do icon assignments for assembling machines in data-updates, with the following function:

function reskins.lib.assign_icons(name, inputs)
    -- inputs required by this function
    -- type            - Entity type
    -- icon            - Table or string defining icon
    -- icon_size       - Pixel size of icons
    -- icon_mipmaps    - Number of mipmaps present in the icon image file

    -- Initialize paths
    local entity = data.raw[inputs.type][name]
    local item = data.raw["item"][name]
    local explosion = data.raw["explosion"][name.."-explosion"]
    local remnant = data.raw["corpse"][name.."-remnants"]

    -- Check whether icon or icons, ensure the key we're not using is erased
    if type(inputs.icon) == "table" then
        -- Create icons that have multiple layers
        if entity then
            entity.icon = nil        
            entity.icons = inputs.icon
        end

        if item then
            item.icon = nil
            item.icons = inputs.icon
        end

        if explosion then 
            explosion.icon = nil        
            explosion.icons = inputs.icon
        end

        if remnant then
            remnant.icon = nil
            remnant.icons = inputs.icon
        end
    else
        -- Create icons that do not have multiple layers
        if entity then
            entity.icons = nil
            entity.icon = inputs.icon
        end

        if item then
            item.icons = nil        
            item.icon = inputs.icon
        end

        if explosion then
            explosion.icons = nil        
            explosion.icon = inputs.icon
        end

        if remnant then
            remnant.icons = nil
            remnant.icon = inputs.icon
        end
    end

    -- Make assignments common to all cases
    if entity then
        entity.icon_size = inputs.icon_size
        entity.icon_mipmaps = inputs.icon_mipmaps          
    end

    if item then
        item.icon_size = inputs.icon_size
        item.icon_mipmaps = inputs.icon_mipmaps 
    end

    if explosion then
        explosion.icon_size = inputs.icon_size
        explosion.icon_mipmaps = inputs.icon_mipmaps
    end

    if remnant then
        remnant.icon_size = inputs.icon_size
        remnant.icon_mipmaps = inputs.icon_mipmaps
    end
end
4 years ago
(updated 4 years ago)

Ahh, right... Your mod would need to load before mine in order to make the necessary edits before I copy them... But also the timing is important. If your edits take place during data-updates, or earlier; them it will be fine, since my mod doesn't copy until data-final-fixes.

If you are also making changes in final-fixes though, then I would simply need to remove the edit, either permanently, or just whenever your mod is loaded.

4 years ago

You could add if not mods["reskins-bobs"] then ...

Or give bob your graphic and be like "Use this menz". It's not that he doesn't care, I don't expect anyone else has cared enough to mention it. Not everyone can be as anal as we. :D

4 years ago

If that's the internal name of your mod, then that'll definitely work!

I'm not so sure about asking another mod to accommodate my personal preferences.. which is partly why I snuck it into this mod lol.

4 years ago

It's up to him if he uses it or not, I imagine he won't mind.

4 years ago

:<
https://i.imgur.com/r5QPFPF.png

Moar static values!

4 years ago

Hm, I'm not sure why you scaling after util.by_pixel doesn't work.

All THAT function does is x/32, y/32...

4 years ago
(updated 4 years ago)

Ah yup, oil refinery is the other entity that uses that problem function, so it's hardcoded as well.

It's a mystery indeed. The scale works fine for all layers, but the shift is always off for the shadow layer specifically, despite the fact that it's running through every layer and applying the same exact 2/3 calculation.

Also, don't think it's util.by_pixel specifically, since other entities use it and 2/3 reduction works just fine. It's the make_4way... function that messes things up.

4 years ago

There are a few functions that Factorio uses that nest things differently. I ran into that myself when I was reskinning the belts.

The specific issue was that instead of being able to find the field I wanted at e.g. animation.layers... I had to find it at animation[1].layers. It was specifically because the particular entity in question was generated with make_rotated_animation_from_layers, and if I had to guess, the exact same thing is happening here.

4 years ago

Have you used this mod?
https://forums.factorio.com/viewtopic.php?t=45107

I've found it really helpful to see what is actually being generated, e.g.: https://i.imgur.com/7BNoyMp.png

4 years ago

This is the dreaded function:

make_4way_animation_from_spritesheet(animation)
    local function make_animation_layer(idx, anim)
      local start_frame = (anim.frame_count or 1) * idx
      local x = 0
      local y = 0
      if anim.line_length then
        y = anim.height * math.floor(start_frame / (anim.line_length or 1))
      else
        x = idx * anim.width
      end
      return
      {
        filename = anim.filename,
        priority = anim.priority or "high",
        x = x,
        y = y,
        width = anim.width,
        height = anim.height,
        frame_count = anim.frame_count or 1,
        line_length = anim.line_length,
        repeat_count = anim.repeat_count,
        shift = anim.shift,
        draw_as_shadow = anim.draw_as_shadow,
        force_hr_shadow = anim.force_hr_shadow,
        apply_runtime_tint = anim.apply_runtime_tint,
        scale = anim.scale or 1,
        tint = anim.tint,
        blend_mode = anim.blend_mode
      }
    end

    local function make_animation_layer_with_hr_version(idx, anim)
      local anim_parameters = make_animation_layer(idx, anim)
      if anim.hr_version and anim.hr_version.filename then
        anim_parameters.hr_version = make_animation_layer(idx, anim.hr_version)
      end
      return anim_parameters
    end

    local function make_animation(idx)
      if animation.layers then
        local tab = { layers = {} }
        for k,v in ipairs(animation.layers) do
          table.insert(tab.layers, make_animation_layer_with_hr_version(idx, v))
        end
        return tab
      else
        return make_animation_layer_with_hr_version(idx, animation)
      end
    end

    return
    {
      north = make_animation(0),
      east = make_animation(1),
      south = make_animation(2),
      west = make_animation(3)
    }
  end
4 years ago

Yeah, I looked into the base game code and already checked the function before; it's a little much for me to follow. As for that mod.. I think I've seen it around, but never actually used it myself. I have a debugging function to output relevant information when I code.

If it's nested one layer deeper, that could be the issue... but then again, why would 2/3 scale work perfectly, but not 2/3 shift?

4 years ago

Looking at the values of shift pre-scaling, shadow has entirely different numbers from everything else, because it's got different dimensions. Perhaps it being shifted by 2/3rds doesn't put it where it needs to be? Dunno. I'm playing around with it myself at the moment.

4 years ago
(updated 4 years ago)

--nvm--

4 years ago
(updated 4 years ago)

--nvm--

New response