Hey man. So I've realized this mod is the source of stuttering in my game (basically every few seconds the game will briefly freeze; shows up in F5 view as a 300ms tick update). The reason why has to do with how you're going through teleporters. After spending a few hours thinking of ways to fix it, I had a fairly decent idea that...actually changes quite a lot about how the mod would work. But tell me what you think regardless.
Instead of having the teleporters have a variable charge time based on distance, have them use an energy buffer. You can then set the size of the buffer and how fast energy is allowed in to control the charge time; this removes the need for modules on the teleporters, and for all the code around 'is_crafting()'. Once the energy buffer is full the teleporter can instantly move items from source to dest. Why would you want to do this? Currently you need to iterate through both source and destination during ontick() calls, this would allow you to update both source and dest at the same time in the same ontick() call, and you'd only ever need to scan through senders. The final piece of this upgrade would be changing find_target to not worry about who is emptiest of them all. Rather, just leave the list static and always send to the first available target. This saves some checking time, but also makes it super clear that more senders are needed on the network; if something in particular is starved and shuts down, it's obvious there is a problem. If is sometimes deemed 'emptiest' as currently happens, it is much harder to figure out you need more production...and checking for emptiest costs more time in the ontick() call which is super sensitive to delays already. :(
"But what if the player wants to make it send faster?" Look into how this mod: https://mods.factorio.com/mod/MFDefenses made upgradable walls and defenses. Basically, you define (in a loop) a bunch of higher tier versions of the sender/receiver (all the various upgraded names would have the same in-game name in the locale file though). Each version has a higher charge rate than the previous one.
So say that you decide you want a teleport to cost 3GJ. Well, if the player has a really tiny base and only 3GW of total power output, and 500MW to spare, then they could charge, at most, at 500MJ/s. Now, maybe the first version of your teleporter only allows that model to charge at 250MJ/s. That's fine, but you'd have research options to increase the charge rate. But that would be a two-edged sword. If the player actually upgraded to the point that they were able to charge at 650MJ/s then they'd actually have massive power problems in their base, so they'd have to be smart about upgrading.
Similarly, as bases get bigger, and accumulator stacks are able to handle massive power spikes better, a large base might be able to let a charge rate of 30GJ/s slide, meaning that each teleporter could send items every 100ms (this would also require the ontick() code to be faster :p, but whatever).
edit: There are three ways to tackle range: 1) Decide you don't want to allow faster charging, ever, and instead make buffer capacity the thing you scale on. Larger buffer = takes longer to charge! 2) Define a large buffer (say, enough for up to 5KM) that doesn't change, but then determine the energy cost to teleport and only subtract that amount from the buffer, rather than emptying it. 3) Have both buffer size and charge rate be upgradable. If someone wants to send really far, they have to put a lot of research in to upgrades needed to get there. Would require a LOT (hundreds? Thousands?) of possible entity prototype definitions. For loops are great, but still...
What are your thoughts?