MightyPirates / OpenComputers

Home of the OpenComputers mod for Minecraft.
https://oc.cil.li
Other
1.59k stars 433 forks source link

Power Advantage #1248

Closed DrPlantabyte closed 9 years ago

DrPlantabyte commented 9 years ago

Hello!

I'm DrCyano, author of the Power Advantage API, and I want to add compatibility between the power systems of your mod and Power Advantage. I'm working on adding an electricity add-on for Power Advantage right now, so this is a good time for me to work on compatibility with Open Computers.

There are three ways we can do this. Method one would be for me to create a converter block that accepts Power Advantage energy types and outputs the energy type used in your mod. Method two is that you could use the Power Advantage API yourself and convert your base machine class to be a simple power consumer (Power Advantage API can do the rest). Method three is that I could try to do the conversion for you and hand you a pull request, but then I'd need to know a little more about how your mod works under-the-hood and I might make changes that you don't like to facilitate compatibility.

Let me know what you prefer, -DrCyano

fnuecke commented 9 years ago

Ohh, dedicated power generation in 1.8? Cool.

I've had a quick look, and saw the TileEntitySimplePowerConsumer and BlockSimplePowerConsumer classes - is the block implementation needed, or could the conduit registration also take place in, say, the first tick of a TE?

I'm asking because OC's power integration is pretty much exclusively geared towards a TileEntity-side implementation (deliberately linking to the 1.7 branch because most of the stuff is commented out in the 1.8 branch). It uses Scala's traits, so unless I'm misremembering something, it should be possible to have a trait PowerAdvantage extends TileEntitySimplePowerConsumer with Common that implements the Power Advantage logic and add that to the PowerAcceptor. Main potential issue there being that I'm not sure that stripping out the trait/interface if PA isn't present would also remove the TileEntitySimplePowerConsumer from the hierarchy - in other words, I'm a bit worried about it not being a fully optional dependency. So in the "worst case" we might have to take a step back and extend PoweredEntity directly. But assuming that works, sure, let's have the integration in OC.

Do you have a Maven to make it easier to add a dependency in the build script? (If need be, a dep on Curseforge also works, ofc.) I prefer to not have external APIs in the repo.

DrPlantabyte commented 9 years ago

Currently, the way Power Advantage works is that when a power source generates energy, it follows the path of touching blocks that implement ITypedConduit, and then polls all TileEntities in that path that extend PoweredEntity. There will be problems if you try to register via TileEntity ticks because the cached network is occasionally invalidated and recomputed.

I am open to modifying Power Advantage to facilitate compatibility. All I need is something about the block that tells me what kind of power it conducts (e.g. "electricity") and some way of asking the tile entity how much power it wants.

What if I added a registry singleton with a method like this (I apologize for not knowing enough Scala to show what that would look like in Scala):

LightweightPowerRegistry.registerPowerAcceptor(Block machine_block, ConduitType energy_type, 
ILightweightPowerAcceptor power_acceptor_implementation);

Where ILightweightPowerAcceptor is defined like this:

public interface ILightweightPowerAcceptor {
  abstract float getDemandForPower(TileEntity acceptor_entity, ConduitType power_type_provided);
}

In this case, you could check if Power Advantage is loaded on mod initialization ( Loader.isModLoaded("poweradvantage") ) and then simply register your blocks and anonymous interface implementations and then I'd handle the rest on my end. Thus your code would look something like this (if it was java)

if( Loader.isModLoaded("poweradvantage") ){
  LightweightPowerRegistry.registerPowerAcceptor(GameRegistry.findBlock("oc", "powerConverter"), new ConduitType("electricity"), new ILightweightPowerAcceptor(){
    public float getDemandForPower(TileEntity te, ConduitType power_type){
      return ((PowerConverter)te).getMaxEnergyStored() - ((PowerConverter)te).getEnergyStored();
    }
  });
}

Would that work for you?

As for Maven scripts and dependencies, I unfortunately have very little experience with Maven (or Gradle, for that matter). If you can pull from GitHub, then that would work, though if you are going to go that route then I'll create a "stable" branch to prevent my tinkering from causing you problems.

fnuecke commented 9 years ago

Ahh, I see.

That suggested API is very nice for an optional implementation, I like it (resembles the BluePower bundled redstone one, to a degree, actually, which was also very nice to integrate with in an optional manner). OC already has a system for mod-presence based initialization of integration stuff, so this would be a perfect fit! The ILightweightPowerAcceptor would probably also have a addEnergy(TileEntity, ...) method, right?

Maven/dependency: good point, I could probably tap into the release download on Github, same principle as what I'm doing via Curseforge really. So that'll work just fine I think.

So yeah, if you can add the API layer you suggested, I can easily add the integration on the OC side! Let me know when / in which version this will be in, and I'll get right on it :)

DrPlantabyte commented 9 years ago

Yes, you're right that the interface would have 2 methods, one to ask for energy and one to receive it. I'll let you know when I get it working.

DrPlantabyte commented 9 years ago

It's done. The light-weight API for Power Advantage is in the cyano.poweradvantage.api.modsupport package. All you gotta do is add something like this to your initializer and Power Advantage will do the rest:

if(Loader.isModLoaded("poweradvantage")){
        LightWeightPowerRegistry.registerLightWeightPowerAcceptor(Blocks.myMachine, 
                new ILightWeightPowerAcceptor(){

                    public boolean canAcceptEnergyType(ConduitType powerType) {
                        return ConduitType.areSameType(powerType, "electricity");
                    }

                    public float getEnergyDemand(TileEntity yourMachine,
                            ConduitType powerType) {
                        TileEntityMyMachine m = (TileEntityMyMachine)yourMachine;
                        return m.getMaxEnergyStored() - m.getEnergyStored();
                    }

                    public float addEnergy(TileEntity yourMachine,
                            float amountAdded, ConduitType powerType) {
                        TileEntityMyMachine m = (TileEntityMyMachine)yourMachine;
                        return m.receiveEnergy(amountAdded);
                    }

        });
    }

I also added creative-only blocks that supply unlimited steam power and electrical power so you can test things out while I work on the actual electrical power mod add-on.

The new light-weight API is now in version 1.2.0 (and later).

Let me know if you have any questions, comments, or concerns.

fnuecke commented 9 years ago

Great! I'll have a look in the evening! One minor suggestion: also pass the TileEntity / block coordinates to canAcceptEnergyType. This is useful for metablocks (i.e. one block representing multiple actual blocks, some of which may accept a certain type of energy, some of which may another or none at all). I think I've split up most blocks in OC in MC1.7, so it won't really affect me, but just for future-proofing I think it'd be better to be more flexible?

DrPlantabyte commented 9 years ago

I could make that change, but all of the data for the light-weight interface are stored in a HashMap using the Block object as the key, not the Blockstate. Meta blocks simply don't make sense in Minecraft 1.8 and will cause a lot of bugs because each orientation counts as a different blockstate. For example, my pipe system has 64 blockstates (6 boolean properties) for each pipe block to render all the possible combinations of connections. If someone was using this pipe system with RF or other TileEntity based power transmission system, they'd have to register 64 ILightWeightPowerAcceptor implementations for that block (128 if the pipes visually changes when holding energy) and 6 for each orientable machine block (12 if the model changes when active).

I agree with your logic, but I'll decline to implement it because the subtle bugs introduced by being so flexible are harder to debug than the bugs caused by the current implementation (also, the other meta blocks could still just not ask for any energy).

fnuecke commented 9 years ago

Ah, all right then, that makes sense!

fnuecke commented 9 years ago

Reopening this so I don't forget about it; sorry, simply didn't get around to it yet. Had hoped to get to it over the weekend, but then BTM happened.

Also, one thing you might be able to help me out with: suggestions for the conversion ratio? E.g. how much RF/fuel time is one unit of PA energy?

Oh, and: did you deliberately decide against side-awareness in the lightweight API?

DrPlantabyte commented 9 years ago

OK, sorry for closing it then.

I don't really know how much work is to be expected from a unit of RF and the power ratio for electricity hasn't been finalized yet, but I always calibrate my power with vanilla Minecraft coal and furnace. So 1 piece of coal powers a furnace for 1600 ticks (smelting an item takes 200 ticks). Steam Advantage produces 1600 units of steam from 1 piece of coal. Electric Advantage will generate 50 000 units of electricity from a piece of coal and consume 3200 units to smelt an item (16 units per tick), thus the conversion ratio from steam to electricity will be about 1:32 (the electricity units are different from steam units to simplify battery storage capacity calculations).

As for sided-ness, the native Power Advantage API is side sensitive, but the translation to RF made it difficult for pipe blockstates to tell the RF tile entities which side they were next to. In the interest of reducing the potential for bugs in the implementation, I'm delaying side-sensitive and multi-powertype implementation until people have used (and found the bugs in) the side-insensitive interface.

If you feel that it is important, I can push the next implementation earlier.

fnuecke commented 9 years ago

Allrighters, thanks for those numbers! OC's energy is essentially what old MJ was, so one coal = 1600 OC energy. So I'll just use the 1:32 ratio. Edit: at least I think it is :P Either way, I'll know what to calibrate against.

Sidedness isn't really required, I wanted to clean that up to also have null be what UNKNOWN was in 1.7 anyway. Was mostly curious. No need to hurry and do it less ideal than you'd want it to be.