dannydjdk / Tiny-Redstone

Forge mod for Minecraft that adds many tiny redstone pieces that you can put together on redstone panels to form tiny redstone circuits.
https://www.curseforge.com/minecraft/mc-mods/tiny-redstone
GNU General Public License v3.0
26 stars 5 forks source link

[Feature request] Make circuits movable with Create contraptions #95

Closed evg-zhabotinsky closed 2 years ago

evg-zhabotinsky commented 2 years ago

I am playing MC 1.18.1. Built an elevator using Create and was going to use Tiny Redstone for the control panel. (At least a button for each floor, sending wirelessly to the control room.)

However, it seems that the the circuits (with or without a panel) are not movable with Create. They stay in place, contraptions pass right through them (like they pass through stationary e.g. torches), and circuits disappear if a contraption reverts to blocks at their location (instead of dropping like e.g. torches).

If it isn't too much work, would be nice to be able to move circuits with contraptions. (E.g. have the control panel inside elevator, instead of on the shaft wall on every floor.) I suspect that making circuits movabe with pistons would suffice for Create too. Making them behave as if they were broken and placed in a new position, keeping only visuals while in transit, would be ok IMO. I also use "circuits" for decorative microblocks, would be nice to have them move visually and collide even if they aren't operational otherwise.

Bonus points if circuits remain operational and interactable while moving, but since even normal redstone doesn't work on moving contraptions... Well, at least [trap]doors and levers can be interacted with while moving, and lever toggle takes effect when contraption reverts to blocks, so it might be possible to keep a circuit working "in isolation" too, maybe even keep tiny wireless transmitters transmitting. But that likely is too much work.

dannydjdk commented 2 years ago

Were your circuits superglued to the contraption? They should move with the contraption, but getting them to function while in transit is probably impossible: not difficult, but actually impossible. Even Create's own wireless redstone doesn't work in transit.

evg-zhabotinsky commented 2 years ago

Yes, superglued. Tried a few different options, including supergluing a circuit panel flat to a chassis so that the elevator would have to run into it, it just goes right through.

My guess is that Create generally only moves "movable" objects, the ones that pistons can move. (It definitely doesn't move obsidian.) And pistons can't move circuits currently.

And since circuits are "non-solid" or something, they don't stop contraptions from moving into their space, and if a contraption reverts to blocks there it breaks the block ("with a hand"?), and when crcuits are broken like that they drop nothing.

dannydjdk commented 2 years ago

Strange. I've tested this in the past, and it worked. The circuits were just disabled during transit. Something must have changed.

Circuits are block entities, which is why they can't be pushed by pistons, but breaking a circuit always results in the circuit dropping, whether you break it by hand, with a wrench or a pickaxe. I wouldn't want players to lose a circuit just because they used the wrong tool to break it. That would be evil. So, Create must be doing something unexpected here and something that it previously did not do.

Can you give me the versions of everything involved: Create, Flywheel, Tiny Redstone, Forge and Minecraft? Also, would you be able to test with other block entities, like a Minecraft furnace, or perhaps a machine from another mod that isn't a full block?

evg-zhabotinsky commented 2 years ago

Okay, maybe I've made a few assumptions here. Will test more thoroughly in the next day or two.

All versions are latest for 1.18.1 as of yesterday, release if available and beta otherwise. And that's not very stable, it seems, only realized that after Forge kept updating almost daily with actual fixes. Will include exact versions with test results.

dannydjdk commented 2 years ago

I was able to reproduce part of what you experienced. My contraptions would not move Tiny Redstone circuits, and they moved right through them. However, they did not break the circuits. I reproduced this both in the latest 1.18.1 and 1.16.5 versions.

Furnaces are successfully moved with contraptions. Interestingly, Tiny Redstone's Block Chopper does move with contraptions, so it's not all block entities. Also, I tried using a covered circuit, which is a full block, and it did not move that. So, there's something special about the circuits that Create says "no, I'm not moving that."

None of the blocks above can be moved by pistons. I suspect that Create probably stopped moving certain types of block entities at some point due to problems and crashes. We need to find out how it distinguishes between moveable and non-moveable ones.

evg-zhabotinsky commented 2 years ago

It was a change in TinyRedstone between 1.16.5-1.10.6 and 1.16.5-1.11.1. The former version results in moving circuits, while with the latter circuits don't move. (MC 1.16.5, Forge and Create latest releases. Also checked oldest Create for 1.16.5 with both oldest and newest TinyRedstone, the results were consistent with this hypothesis.)

dannydjdk commented 2 years ago

Ah. That's interesting and super helpful! Thanks for the research! There were a lot of changes to voxel shapes in that update, none I would have expected to affect Create, but this definitely gives me a good place to start investigating.

evg-zhabotinsky commented 2 years ago

I did some testing, circuits move now. Create just ignores blocks with empty collision shapes. (probably this is responsible)

Any ideas why the shape was empty in the first place and how to fix it? The collision now is a tiny cube at the center of the block when it is on a moving contraption. It seems that the custom shape never worked with Create, PanelBlock.getCollisionShape() just can't get its own PanelTile block entity for some reason.

dannydjdk commented 2 years ago

The issue is that the PanelBlock voxel shape is dynamic. It doesn't know what shape it will be until after a component is placed. It needs the PanelTile entity to calculate where the tiny component will place. Create contraptions query for the voxel shape once before it gets placed. The shape was empty to prevent culling of adjacent block rendering and to allow the player to stand within the block space when placing the first component.

My solution was to make the pre-placement shape the tiny cube in the center of the block. It's the most unlikely place that a player would be standing while placing. However, I'm not entirely satisfied with this solution and am still considering other alternatives. The problem is that the player could be standing at that spot and will have no idea why they can't place the first component. Intuitively, most players would move around a little to try to place from a slightly different angle which would work, but it's not ideal.

The ideal solution would be to calculate the voxel shape prior to placement somehow, but there are a number of obstacles, and a few different conditions to account for.

  1. If the player is placing a component in the world, it needs to calculate the location based on the player's hit vector. This is difficult without a block entity.
  2. If the player is placing a panel or a circuit with a panel, it would be easy enough to just use the voxel shape of the base.
  3. If the player is placing a circuit without a panel, it needs to calculate the voxel shape of the circuit prior to placement. Again, difficult without the block entity, especially since the existing voxel shape calculations exist within the PanelTile class.
  4. If a non-player is placing the panel (such as the when the Create contraption stops and becomes blocks again), again, we have to calculate the voxel shape before the block entity exists.

So, there are 2 main tasks:

  1. Determine player hit vector without the block entity and determine placement location within the block space.
  2. Calculate PanelBlock's voxel shape without a block entity object, probably with a static, context free method something like: calculateShape(CompountNBT cellData, Direction facing, Boolean hasBase)
dannydjdk commented 2 years ago

Actually, task 2 is not really needed. Since we only need a non-empty voxel shape, and one that doesn't interfere with the player's position, we only need to do task 1.

evg-zhabotinsky commented 2 years ago
  1. How about getting actual shape pre-placement only when NOT placing a component into empty spesace? I.e. when placing a panel or a pre-made circuit. Then you can figure out the orientation just like you did before v1.11. And for placing components into empty space leave collision empty.
  2. Is actually needed, I think, because the circuit keeps that hacky collision shape while the contraption is in transit, and it can stay in transit for a looong while.
dannydjdk commented 2 years ago
  1. Before v1.11, it was just calculating the base panel shape before placement: component voxels were calculated afterwards. It would be easy enough to reimplement this for panels that do have a base. The problem is with circuits that don't have a base (a feature that didn't exist prior to v1.11). That shape may not be valid, and may cause confusing placement restrictions.
  2. Yes, this is ideal. However, it is only necessary because of the way Create obtains and retains the voxel shape prior to placement. There is otherwise no reason to even have a voxel shape at that point. I definitely want to make this work, but given the amount of work involved, the very limited amount of time I have to work on it, and the other features still on my to do list, this may have to sit low on my priority list.

Even after doing all of the work above, since Create is getting the shape prior to placement, and never after, if you build a circuit on a Create contraption, any new components you add will not be a part of that original voxel shape. You would have to break and replace it any time you make a change.

This makes me wonder about Chisels & Bits. What happens if you place a few bits on a contraption and then make it larger? Does that get updated dynamically? If so, I can see if C&B is doing something special to update it's neighbors about voxel changes. If not, I give up.

evg-zhabotinsky commented 2 years ago

I think I will try to make it work "properly" with Create, then.

In Create you can't build anything, circuits included, on a contraption when it is movable, and when it is fully stopped it is just blocks and Create forgets them. So the shape changing isn't a problem, because it can't change, once a contraption is assembled it is "frozen" more or less.

And about circuits without a panel, I mentioned 1.10 because placing a whole circuit, with a panel or without, is just placing a whole block, so you don't need to worry about where exactly the player is pointing. If I'm not mistaken, panel-less circuits should be even easier, you can't change their orientation when placing. Still need to figure out how to calculate the shape, though.

Maybe it would be easier to handle on Create's side, too.

dannydjdk commented 2 years ago

The problem is that Create is getting the voxel shape from before the block is placed. So, changing the circuit is a problem. It appears that Minecraft is caching collision shapes for the block state. This might be the issue. I'm not sure why that cache would only affect Create and not player interactions. But, it would be strange for Create to actually query the voxel shape prior to placement. Seems like it would make a lot more sense to do that when the contraption becomes an entity.

It would be helpful to do some debugging here just to find out how and when the voxel shape is being queried. The ideal outcome would be for Create to always get an updated version of the voxel shape. Trying to pre-generate the voxel shape of a dynamically shaped block is just asking for more issues down the road. Ideally, we want the collision of the contraption to be the same as the collision of the PanelBlock even if it's edited after placement. This means I need to get Create to work in my dev environment which has been a problem in the past due to some mixin issues.

There are some additional issues with the workaround I outlined above (several comments ago). One, when a contraption turns back into blocks, we have absolutely no data until the block entity is created. Two, when calculating the collision shape, we don't have any player data, so getting the look vector isn't just difficult, it's probably impossible. Three, it doesn't solve the issue of Create not getting shape updates after placement. That's really the problem that needs to be solved.

evg-zhabotinsky commented 2 years ago

This helped me get Create running in TinyRedstone dev:

diff --git a/build.gradle b/build.gradle
index d015414..31642dc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -55,6 +55,9 @@ minecraft {
             // Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
             property 'forge.logging.console.level', 'debug'

+            property 'mixin.env.remapRefMap', 'true'
+            property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg"
+
             mods {
                 tinyredstone {
                     source sourceSets.main
@@ -135,7 +138,7 @@ dependencies {
     // Specify the version of Minecraft to use. If this is any group other than 'net.minecraft', it is assumed
     // that the dep is a ForgeGradle 'patcher' dependency, and its patches will be applied.
     // The userdev artifact is a special name and will get all sorts of transformations applied to it.
-    minecraft 'net.minecraftforge:forge:1.18.1-39.0.0'
+    minecraft 'net.minecraftforge:forge:1.18.1-39.0.46'

     //implementation fg.deobf('curse.maven:theoneprobe-245211:3430022')

@@ -145,6 +148,8 @@ dependencies {

     //implementation fg.deobf('curse.maven:redstonepen-461710:3480057')

+    implementation fg.deobf('curse.maven:flywheel-486392:3623314')
+    implementation fg.deobf('curse.maven:create-328085:3623348')
 }

 // Example for how to get properties into the manifest for reading at runtime.

About all the rest: As I said, I will try looking into it more, a bit later. So better focus on the more important stuff. (Apparently, no one even tried moving circuits with contraptions since 1.10, or at least they didn't report.)

evg-zhabotinsky commented 2 years ago

Or maybe for debugging purposes it would be better to build an unobfuscated jar for Create and throw it into mods folder. I only did it the other way around, though, unobfuscated TinyRedstone jar into mods folder in Create dev. (./gradlew jar after commenting jar.finalizeBy('reobfJar') in build.gradle)

dannydjdk commented 2 years ago

I got it with curse.maven. I was missing the mixin properties you included. That fixed it for me.

I found the problem. When calling the getCollisionShape on a blockstate without including a CollisionContext, Minecraft just gives you the cached collision shape for the block state, not the specific block. So, the only way that we could possibly get the accurate voxel shape is if Create were to call state.getCollisionShape(world, pos, context) where context is a non-empty CollisionContext.

The workaround we can do in Tiny Redstone is to return some default shape when PanelBlock.getCollisionShape is called when a PanelTile doesn't exist and the CollisionContext is empty. Minecraft calls it this way to set the cache. If there's a base (which is defined in the block state), the shape can be the base shape. If there isn't, I'll probably just provide a box in the middle of the block space. That's probably the best we can do. I'm pretty sure there's no way to override that caching behavior.

dannydjdk commented 2 years ago

Fix/workaround has been released in all 3 versions. If Create fixes things on their end, you'll get the exact dynamic voxel shape. No need to change anything on my end. For now, they will work in contraptions, but with the default collision shapes.