mt-mods / technic

Technic mod for Minetest
18 stars 25 forks source link

Drop charge value completely #239

Closed S-S-X closed 3 years ago

S-S-X commented 3 years ago

Made another PR for this to make it cleaner and because new PR was not that expensive (and I wanted to have separate branch locally). Tests at least passed unmodified but current tests are not covering that much... also link #233

@OgelGames

Bonus: this should be also option with best possible performance and minimum complexity. API wont change (from what it is at target PR).

S-S-X commented 3 years ago

Ofc managed to push syntax error and luacheck failure but this would be inaccurate energy storage. Range guards can be added if needed but I think it is not needed (should try what happens if stack:set_wear(x) is called with invalid values.

If it wont crash then I would not add guards but require tools to provide correct numbers.

S-S-X commented 3 years ago

Well, seems I got values backwards but basic idea works. Just little issue with using tool charges it and charging in bb discharges 🤣 Requires few adjustments to calculations but other than that seems fine.

S-S-X commented 3 years ago

Oh... actually wear value 0 is no wear at all and 1 is max condition, so that's where problem is actually (in addition to having it backwards). So have to go from 1 to 65535 + 1 for overflow instead of 0-65535.

Somehow I was thinking that 65535 is pristine and towards zero is "broken" tool. And also that's why tests are passing even while it works backwards: it is just visuals that are backwards...

S-S-X commented 3 years ago

Maybe I'll still work on this a bit and try to make sure that technic.use_RE_charge will always add at least single point to wear. Other than that only "problem" I can see is with extremely high max charge combined with extremely low charge per but have not yet seen tools where this matters. If there's tool that has over 65535 individual uses from full charge then that one would not work well (it will be limited to 65535 uses).

edit. technic.get_RE_charge/technic.set_RE_charge users working with tools that have higher than 65535 uses will need to handle big numbers themselves. Only technic.use_RE_charge would be simple "always-guaranteed" charge use method.

S-S-X commented 3 years ago

Tool charging and discharging rate is high enough to not be likely source of problems. Would be still good to check that input / output error is small enough to not be significant (so that abusing it wont be useful) and maybe even make it always lose charge instead of gaining (so that abusing it would just simulate battery stress and losses).

S-S-X commented 3 years ago

I think I'll merge this and continue testing on main branch.

Upsides:

Downsides:

edit. Actually I found one tool going over this limit, from technic_addons:

Chainsaw MK3: Holds 1,000,000 EU and uses 10 EU/node

OgelGames commented 3 years ago

Yeah, I think the upsides far outweigh that one downside 👍

try to make sure that technic.use_RE_charge will always add at least single point to wear

That can be done simpler; round when getting the charge, but floor when setting it: (tested with high-charge tool)

function technic.set_RE_charge(stack, charge)
    if charge < 1 then
        stack:set_wear(0)
    else
        local max_charge = stack:get_definition().max_charge
        stack:set_wear(65536 - math.floor(charge * 65535 / max_charge))
    end
end

function technic.get_RE_charge(stack)
    local wear = stack:get_wear()
    if wear < 1 then
        return 0
    else
        local max_charge = stack:get_definition().max_charge
        return math.floor((65536 - wear) * max_charge / 65535 + 0.5)
    end
end

function technic.use_RE_charge(stack, amount)
    if technic.creative_mode or amount < 1 then
        return true
    end
    local charge = technic.get_RE_charge(stack)
    if charge < amount then
        return false
    end
    technic.set_RE_charge(stack, charge - amount)
    return true
end
S-S-X commented 3 years ago

try to make sure that technic.use_RE_charge will always add at least single point to wear

That can be done simpler; round when getting the charge, but floor when setting it: (tested with high-charge tool)

function technic.set_RE_charge(stack, charge)
  if charge < 1 then
      stack:set_wear(0)
  else
      local max_charge = stack:get_definition().max_charge
      stack:set_wear(65536 - math.floor(charge * 65535 / max_charge))
  end
end

function technic.get_RE_charge(stack)
  local wear = stack:get_wear()
  if wear < 1 then
      return 0
  else
      local max_charge = stack:get_definition().max_charge
      return math.floor(((65536 - wear) * max_charge / 65535) + 0.5)
  end
end

function technic.use_RE_charge(stack, amount)
  if technic.creative_mode or amount < 1 then
      -- Do not check charge in creative mode or when trying to use zero amount
      return true
  end
  local charge = technic.get_RE_charge(stack)
  if charge < amount then
      -- Not enough energy available
      return false
  end
  technic.set_RE_charge(stack, charge - amount)
  -- Charge used successfully
  return true
end

This seems to make it way less accurate than using custom floating point math:

Charging 6 rounds, 10kEU / cycle. Result: error is way higher.

Failure → spec/tools_spec.lua @ 201
Technic power tool charging and discharging extreme ratios t1_65536 can be charged
spec/tools_spec.lua:207: Expected objects to be equal.
Passed in: (number) 59997 Expected: (number) 60000

Charging 7 rounds, 10kEU / cycle. Result: error is way higher.

Failure → spec/tools_spec.lua @ 223
Technic power tool charging and discharging extreme ratios t100_6553600 can be charged
spec/tools_spec.lua:231: Expected (number) 69998 to be less than (number) 69501

Using extreme ratio tools, 7 rounds, 100 per use, initial charge 700, expected after 6 round: 100, expected after 7 rounds 0. Result: stack destroyed.

Failure → spec/tools_spec.lua @ 235
Technic power tool charging and discharging extreme ratios t100_6553600 can be used
mineunit/itemstack.lua:29: ItemStack:set_wear invalid wear value: 65536
S-S-X commented 3 years ago

These tools registered for tests have extreme max_charge to use ratios (and use values that are likely to cause errors with rounding) like mymod:t100_6553600 has max_charge = 6553600 and calls technic.use_RE_charge(stack, 100). And mymod:t1_65536 has max_charge = 65536 and calls technic.use_RE_charge(stack, 1).

S-S-X commented 3 years ago

That Chainsaw MK3 from technic_addons actually also somewhat works when cutting large enough area, anything more than just few nodes.

21 x 11 x 21 area actual charge used 48508 where accurate use would be 48510 (10 per node).

Took some time... Mineunit is pretty slow cutting trees with chainsaw 🥼

OgelGames commented 3 years ago

Ah, I see the problem with my code, it floors the value when charging, but it should only floor it when using it, and round when charging.

S-S-X commented 3 years ago

Also stack:set_wear(65536 - math.floor(charge * 65535 / max_charge)) sets invalid value for charge = 1. edit. Well, that's exactly what you were talking about 🤦

But I've not found problems with current code so unless you got something some a lot simpler solution then I guess current is what should be used.

S-S-X commented 3 years ago

Well, cleaned up negative wear value hack (while kind of nice not sure if it is really safe with engine updates...). Also made it calculate conversion factor during registration and use it instead of max_charge.

S-S-X commented 3 years ago

Maybe max_charge should also be technic_max_charge instead...

OgelGames commented 3 years ago

But I've not found problems with current code so unless you got something some a lot simpler solution then I guess current is what should be used.

There is one problem, set_RE_charge doesn't do the wear check. I think it should be moved out of use_RE_charge and into set_RE_charge.

This code should work for that: (idk how to run tests locally)

function technic.set_RE_charge(stack, charge)
    local wear = 65536 - charge * stack:get_definition().technic_wear_factor
    stack:set_wear(wear > stack:get_wear() and math.ceil(wear) or math.floor(wear + 0.5))
end
github-actions[bot] commented 3 years ago
Click for detailed source code test coverage report ### Test coverage report for Technic CNC 79.01% in 10/14 files: ``` File Hits Missed Coverage ----------------------------------------------------- programs.lua 263 0 100.00% materials/basic_materials.lua 17 0 100.00% materials/default.lua 177 4 97.79% cnc.lua 50 3 94.34% materials/init.lua 13 1 92.86% formspec.lua 103 8 92.79% digilines.lua 39 8 82.98% init.lua 19 6 76.00% api.lua 160 83 65.84% pipeworks.lua 25 13 65.79% materials/technic_worldgen.lua 0 25 0.00% materials/moreblocks.lua 0 29 0.00% materials/ethereal.lua 0 37 0.00% materials/bakedclay.lua 0 13 0.00% ``` ### Test coverage report for technic chests 45.24% in 6/6 files: ``` File Hits Missed Coverage ---------------------------------- chests.lua 98 18 84.48% init.lua 34 18 65.38% register.lua 84 78 51.85% formspec.lua 76 93 44.97% inventory.lua 10 100 9.09% digilines.lua 2 61 3.17% ``` ### Test coverage report for technic 65.68% in 118/118 files: ``` File Hits Missed Coverage -------------------------------------------------------------- max_lag.lua 12 0 100.00% machines/register/init.lua 22 0 100.00% machines/register/grinder.lua 6 0 100.00% machines/register/freezer_recipes.lua 13 0 100.00% machines/register/freezer.lua 6 0 100.00% machines/register/extractor.lua 6 0 100.00% machines/register/electric_furnace.lua 6 0 100.00% machines/register/compressor.lua 6 0 100.00% machines/register/centrifuge.lua 6 0 100.00% machines/other/init.lua 8 0 100.00% machines/MV/solar_array.lua 9 0 100.00% machines/MV/init.lua 17 0 100.00% machines/MV/grinder.lua 8 0 100.00% machines/MV/generator.lua 9 0 100.00% machines/MV/freezer.lua 8 0 100.00% machines/MV/extractor.lua 8 0 100.00% machines/MV/electric_furnace.lua 8 0 100.00% machines/MV/compressor.lua 8 0 100.00% machines/MV/centrifuge.lua 14 0 100.00% machines/MV/battery_box.lua 17 0 100.00% machines/MV/alloy_furnace.lua 8 0 100.00% machines/LV/solar_array.lua 8 0 100.00% machines/LV/init.lua 17 0 100.00% machines/LV/grinder.lua 9 0 100.00% machines/LV/generator.lua 9 0 100.00% machines/LV/electric_furnace.lua 8 0 100.00% machines/LV/compressor.lua 13 0 100.00% machines/LV/battery_box.lua 15 0 100.00% machines/LV/alloy_furnace.lua 8 0 100.00% machines/HV/solar_array.lua 8 0 100.00% machines/HV/init.lua 12 0 100.00% machines/HV/grinder.lua 8 0 100.00% machines/HV/generator.lua 9 0 100.00% machines/HV/electric_furnace.lua 8 0 100.00% machines/HV/compressor.lua 8 0 100.00% machines/HV/battery_box.lua 17 0 100.00% legacy.lua 33 0 100.00% items.lua 107 0 100.00% crafts.lua 133 0 100.00% ../technic_worldgen/nodes.lua 109 0 100.00% ../technic_worldgen/crafts.lua 103 0 100.00% ../technic_worldgen/config.lua 9 0 100.00% ../technic_cnc/programs.lua 263 0 100.00% ../technic_cnc/materials/technic_worldgen.lua 32 0 100.00% ../technic_cnc/materials/init.lua 14 0 100.00% ../technic_cnc/materials/basic_materials.lua 17 0 100.00% machines/LV/led.lua 73 1 98.65% ../technic_cnc/materials/default.lua 178 4 97.80% machines/register/compressor_recipes.lua 36 1 97.30% machines/LV/geothermal.lua 75 3 96.15% config.lua 49 2 96.08% machines/LV/solar_panel.lua 42 2 95.45% machines/register/solar_array.lua 40 2 95.24% machines/register/cables.lua 208 12 94.55% ../technic_cnc/cnc.lua 50 3 94.34% tools/init.lua 13 1 92.86% machines/LV/water_mill.lua 67 6 91.78% machines/network.lua 323 31 91.24% machines/register/grindings.lua 42 5 89.36% machines/LV/lamp.lua 110 14 88.71% ../technic_worldgen/overrides.lua 39 5 88.64% init.lua 31 4 88.57% machines/register/grinder_recipes.lua 106 16 86.89% ../technic_worldgen/rubber.lua 64 10 86.49% ../technic_worldgen/init.lua 19 3 86.36% ../technic_worldgen/oregen.lua 155 28 84.70% register.lua 26 5 83.87% tools/flashlight.lua 64 13 83.12% machines/register/battery_box.lua 223 53 80.80% machines/register/machine_base.lua 164 41 80.00% ../technic_cnc/formspec.lua 88 23 79.28% ../technic_cnc/init.lua 19 6 76.00% machines/register/recipes.lua 62 20 75.61% machines/switching_station.lua 76 25 75.25% machines/register/centrifuge_recipes.lua 21 7 75.00% ../technic_cnc/api.lua 194 66 74.62% effects.lua 5 2 71.43% radiation.lua 245 100 71.01% machines/LV/extractor.lua 11 5 68.75% machines/MV/wind_mill.lua 46 22 67.65% machines/other/coal_furnace.lua 2 1 66.67% machines/supply_converter.lua 93 48 65.96% ../technic_cnc/pipeworks.lua 25 13 65.79% machines/switching_station_globalstep.lua 40 21 65.57% machines/register/alloy_recipes.lua 28 15 65.12% machines/other/injector.lua 72 39 64.86% tools/multimeter.lua 130 78 62.50% machines/MV/hydro_turbine.lua 43 26 62.32% machines/MV/tool_workshop.lua 56 34 62.22% machines/register/generator.lua 122 88 58.10% tools/cans.lua 53 48 52.48% machines/power_monitor.lua 40 38 51.28% tools/mining_lasers.lua 36 35 50.70% machines/other/coal_alloy_furnace.lua 63 63 50.00% machines/LV/music_player.lua 46 46 50.00% machines/other/constructor.lua 67 69 49.26% machines/MV/cables.lua 10 11 47.62% machines/LV/cables.lua 10 11 47.62% machines/init.lua 49 54 47.57% tools/tree_tap.lua 24 27 47.06% machines/HV/cables.lua 9 11 45.00% tools/vacuum.lua 16 20 44.44% machines/register/common.lua 50 64 43.86% helpers.lua 51 74 40.80% machines/HV/forcefield.lua 101 157 39.15% machines/HV/quarry.lua 124 217 36.36% machines/HV/nuclear_reactor.lua 116 208 35.80% machines/register/alloy_furnace.lua 10 20 33.33% tools/sonic_screwdriver.lua 16 33 32.65% tools/chainsaw.lua 37 80 31.62% machines/other/frames.lua 184 445 29.25% machines/compat/tools.lua 5 13 27.78% tools/mining_drill.lua 63 197 24.23% machines/other/anchor.lua 14 74 15.91% tools/prospector.lua 14 90 13.46% machines/compat/digtron.lua 4 38 9.52% util/throttle.lua 1 10 9.09% machines/register/extractor_recipes.lua 6 65 8.45% ``` ### Raw test runner output for geeks: CNC: ``` ●●●●●●●●●●●●●●●●●●●●●● 22 successes / 0 failures / 0 errors / 0 pending : 0.181241 seconds ``` Chests: ``` W: Configuration: invalid key exclude_textures W: Configuration: invalid key validate_textures ●●●●● 5 successes / 0 failures / 0 errors / 0 pending : 0.036541 seconds ``` Technic: ``` ●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●●◌●●●●●●●●●●●●●●●●●●●●●●●●●● 190 successes / 0 failures / 0 errors / 1 pending : 7.93039 seconds Pending → spec/supply_converter_spec.lua @ 78 Supply converter building overloads network spec/supply_converter_spec.lua:78: overload does not work with supply converter ```
S-S-X commented 3 years ago

But I've not found problems with current code so unless you got something some a lot simpler solution then I guess current is what should be used.

There is one problem, set_RE_charge doesn't do the wear check. I think it should be moved out of use_RE_charge and into set_RE_charge.

This code should work for that: (idk how to run tests locally)

function technic.set_RE_charge(stack, charge)
  local wear = 65536 - charge * stack:get_definition().technic_wear_factor
  stack:set_wear(wear > stack:get_wear() and math.ceil(wear) or math.floor(wear + 0.5))
end

What do you mean by "wear check"? Always rounding and possibly getting "over charged"?

t100_6553600 gets charged too much. not charged enough, error increased (smaller error is already causing loss). t1_65536 charge is not accurate anymore (very small error, just 1EU). t100_6553600 lost energy worth 7 charges after used 6 times. chainsawmk3 accuracy is worse, deviating way more from exact expected use (this might be caused just because of value is bad for testing, I did not really check chainsawmk3 tests but just throwed in copying multimeter test and adding some trees).

I should add few more tests that especially try to abuse charging to gain more than what was pushed from BB as current set does not do that as much.

S-S-X commented 3 years ago

For "how to run tests locally", I'm pretty sure Mineunit is not compatible with Windows so either Windows 10 WSL should be used or some virtual machine running some Linux distro. From command line you'd just install Mineunit from Luarocks: luarocks install --server=https://luarocks.org/dev mineunit and run it in mod source directory with: cd mods/technic/technic and mineunit

S-S-X commented 3 years ago

I should add few more tests that especially try to abuse charging to gain more than what was pushed from BB as current set does not do that as much.

Yeah, just what I thought. Error in these cases generates small amounts of free energy, however that error is way smaller which indicates that presented idea for technic.set_RE_charge might be correct but calculations done with inaccurate values rounded too early and used in calculations after rounding.

No idea what exactly is causing this, I kind of accepted that error as insignificant but not sure how significant it actually could be. Did not check at all. ...has to be just actual numbers used in tests, and only thing I did not check to other direction.

OgelGames commented 3 years ago

What do you mean by "wear check"? Always rounding and possibly getting "over charged"?

This: https://github.com/mt-mods/technic/blob/d51c4dd8ff60d38d16f7c0d49d41d8ec0cc366ac/technic/helpers.lua#L85-L88

Will all these errors I'm wondering if maybe this isn't such a good idea after all... metadata values seem so much better now...

From command line you'd just install Mineunit from Luarocks: luarocks install --server=https://luarocks.org/dev mineunit

Hmm, I think I've got Luarocks, I'll have a look into that.

S-S-X commented 3 years ago

Well, of course error is larger because it tries to always go into one direction. I think that's probably not significant because error is similar for both charging and discharging. Probably real reason to do it would be "battery condition simulation" I mentioned which would be bit more complicated anyway and would like to have required maintenance for tools.

S-S-X commented 3 years ago

What do you mean by "wear check"? Always rounding and possibly getting "over charged"?

This:

https://github.com/mt-mods/technic/blob/d51c4dd8ff60d38d16f7c0d49d41d8ec0cc366ac/technic/helpers.lua#L85-L88

Will all these errors I'm wondering if maybe this isn't such a good idea after all... metadata values seem so much better now...

I don't see any significant errors there, could you give some example data to make it easier to understand?

OgelGames commented 3 years ago

I don't see any significant errors there, could you give some example data to make it easier to understand?

I mean the errors/inaccuracies in charge values, not errors in the code.

S-S-X commented 3 years ago

So far I've only seen errors increase after testing code suggested in comments while with original code I've only seen errors (which are smaller) balancing out between charge / discharge cycles.

S-S-X commented 3 years ago

I think it would be possible to increase accuracy further with error correction by interpolation based on before/after error difference. Basically if there's error then do linear interpolation for errors wear before/wear after and remove that from value calculated with inaccurate scaled values.

Does this sound about right? This is based on assumption that last change was same as current (which is true for charging and discharging for all but last cycle). Also it is of course balancing instead of direct correction because there simply is not enough data for direct correction.

Also I have not really tested current code in game yet so not sure if it is even needed but probably good to have note here at least.

BuckarooBanzay commented 3 years ago

I merged this PR into the test-server and did some tests with various power-tools (using, discharging, recharging) everything works as expected :+1:

S-S-X commented 3 years ago

Tested charging / discharging tools in loop, for me it seems to be very good. More comments on Discord https://discord.com/channels/513329453741637637/816367895621795861/909717067677175808

It seems like even if there's probably some combinations with exact values it wont be enough to make batterybox + powertool power plants viable, it is simply too slow and it should be easy to if needed because having only wear value leaves all upgrade options open without additional cleanup or leftover data.

It seems that energy losses during charge and recharge are not affecting normal use.