From 83657bbc1828ff0b0302ee0fc57284c0a2ba222c Mon Sep 17 00:00:00 2001 From: hinyb <40139991+hinyb@users.noreply.github.com> Date: Tue, 16 Dec 2025 05:44:45 +0800 Subject: [PATCH 1/2] feat(MatterManipulator): Add integration for MatterManipulator. The basic integration is in place, but methods like `GetRequiredItems` which require a player are not implemented yet. --- dependencies.gradle | 1 + .../li/cil/oc/common/tileentity/Robot.scala | 8 +- .../scala/li/cil/oc/integration/Mods.scala | 3 + .../ConvertMatterManipulator.scala | 20 ++ .../DriverMatterManipulator.scala | 275 ++++++++++++++++++ .../ModMatterManipulator.scala | 13 + .../integration/util/MatterManipulator.scala | 26 ++ .../scala/li/cil/oc/server/agent/Player.scala | 9 +- 8 files changed, 351 insertions(+), 4 deletions(-) create mode 100644 src/main/scala/li/cil/oc/integration/matter_manipulator/ConvertMatterManipulator.scala create mode 100644 src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala create mode 100644 src/main/scala/li/cil/oc/integration/matter_manipulator/ModMatterManipulator.scala create mode 100644 src/main/scala/li/cil/oc/integration/util/MatterManipulator.scala diff --git a/dependencies.gradle b/dependencies.gradle index c6e69641d5..71f12c0b3b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -31,6 +31,7 @@ dependencies { compileOnly("com.github.GTNewHorizons:TinkersMechworks:0.4.1:dev") {transitive = false} compileOnly("com.github.GTNewHorizons:waila:1.9.15:dev") {transitive = false} compileOnly("com.github.GTNewHorizons:WirelessRedstone-CBE:1.7.1:dev") {transitive = false} + compileOnly("com.github.GTNewHorizons:MatterManipulator:0.1.4-GTNH:dev") compileOnly("api:coloredlightscore:1") compileOnly("com.bluepowermod:BluePower:0.2.928:deobf") {transitive = false} diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index 14803b39d4..65d881ef28 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -591,7 +591,13 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand } } - override def isComponentSlot(slot: Int, stack: ItemStack) = (containerSlots ++ componentSlots) contains slot + override def isComponentSlot(slot: Int, stack: ItemStack): Boolean = { + ((containerSlots ++ componentSlots) contains slot) || + (Option(Driver.driverFor(stack, getClass)) match { + case Some(driver) => driver.slot(stack) == Slot.Tool + case _ => false + }) + } def containerSlotType(slot: Int) = if (containerSlots contains slot) { val stack = info.containers(slot - 1) diff --git a/src/main/scala/li/cil/oc/integration/Mods.scala b/src/main/scala/li/cil/oc/integration/Mods.scala index 886a80787e..2e5d7e41e4 100644 --- a/src/main/scala/li/cil/oc/integration/Mods.scala +++ b/src/main/scala/li/cil/oc/integration/Mods.scala @@ -51,6 +51,7 @@ object Mods { val IndustrialCraft2 = new SimpleMod(IDs.IndustrialCraft2) val IndustrialCraft2Classic = new SimpleMod(IDs.IndustrialCraft2Classic) val IngameWiki = new SimpleMod(IDs.IngameWiki, version = "@[1.1.3,)") + val MatterManipulator = new SimpleMod(IDs.MatterManipulator) val Mekanism = new SimpleMod(IDs.Mekanism) val MekanismGas = new SimpleMod(IDs.MekanismGas) val Minecraft = new SimpleMod(IDs.Minecraft) @@ -114,6 +115,7 @@ object Mods { integration.gc.ModGalacticraft, integration.gregtech.ModGregtech, integration.ic2.ModIndustrialCraft2, + integration.matter_manipulator.ModMatterManipulator, integration.mekanism.ModMekanism, integration.mekanism.gas.ModMekanismGas, integration.mfr.ModMineFactoryReloaded, @@ -204,6 +206,7 @@ object Mods { final val IndustrialCraft2Classic = "IC2-Classic" final val IndustrialCraft2Spmod = "IC2-Classic-Spmod" final val IngameWiki = "IGWMod" + final val MatterManipulator = "matter-manipulator" final val Mekanism = "Mekanism" final val MekanismGas = "MekanismAPI|gas" final val Minecraft = "Minecraft" diff --git a/src/main/scala/li/cil/oc/integration/matter_manipulator/ConvertMatterManipulator.scala b/src/main/scala/li/cil/oc/integration/matter_manipulator/ConvertMatterManipulator.scala new file mode 100644 index 0000000000..941b96adac --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/matter_manipulator/ConvertMatterManipulator.scala @@ -0,0 +1,20 @@ +package li.cil.oc.integration.matter_manipulator + +import com.recursive_pineapple.matter_manipulator.common.items.manipulator.Location +import li.cil.oc.api.driver.Converter + +import java.util +import scala.collection.convert.WrapAsScala._ + +class ConvertMatterManipulator extends Converter{ + override def convert(value: Any, output: util.Map[AnyRef, AnyRef]): Unit = { + value match { + case location: Location => { + output += "x" -> Int.box(location.x) + output += "y" -> Int.box(location.y) + output += "z" -> Int.box(location.z) + } + case _ => + } + } +} \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala b/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala new file mode 100644 index 0000000000..19270d939c --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala @@ -0,0 +1,275 @@ +package li.cil.oc.integration.matter_manipulator + +import com.recursive_pineapple.matter_manipulator.common.items.manipulator.MMState.PlaceMode._ +import com.recursive_pineapple.matter_manipulator.common.items.manipulator.MMState._ +import com.recursive_pineapple.matter_manipulator.common.items.manipulator.{ItemMatterManipulator, Location, MMState, Transform} +import com.recursive_pineapple.matter_manipulator.common.utils.MMUtils +import li.cil.oc.api.Network +import li.cil.oc.api.internal.Agent +import li.cil.oc.api.machine.{Arguments, Callback, Context} +import li.cil.oc.api.network.{EnvironmentHost, Visibility} +import li.cil.oc.api.prefab.{DriverItem, ManagedEnvironment} +import li.cil.oc.common.Slot +import li.cil.oc.util.ResultWrapper.result +import net.minecraft.item.ItemStack +import net.minecraftforge.common.util.ForgeDirection +import org.joml.Vector3i + +class DriverMatterManipulator extends DriverItem { + override def worksWith(stack: ItemStack): Boolean = stack.getItem.isInstanceOf[ItemMatterManipulator] + + override def createEnvironment(stack: ItemStack, host: EnvironmentHost): ManagedEnvironment = new Environment(stack, host) + + override def slot(stack: ItemStack): String = Slot.Tool + + class Environment(val stack: ItemStack, val host: EnvironmentHost) extends ManagedEnvironment { + val item: ItemMatterManipulator = stack.getItem.asInstanceOf[ItemMatterManipulator] + setNode(Network.newNode(this, Visibility.Network).withComponent("matter_manipulator").create) + val agent: Agent = host.asInstanceOf[Agent] + val state: MMState = ItemMatterManipulator.getState(stack) + + @Callback(doc = "function():number -- Get the charge.") + def getCharge(context: Context, arguments: Arguments) = result(item.getCharge(stack)) + + @Callback(doc = "function(mode: [COPYING, EXCHANGING, GEOMETRY, MOVING, CABLES]: string):boolean -- Set the place mode.") + def setPlaceMode(ctx: Context, args: Arguments): Array[AnyRef] = { + val new_mode = PlaceMode.valueOf(args.checkString(0)) + val requiredBit = new_mode match { + case COPYING => ItemMatterManipulator.ALLOW_COPYING + case EXCHANGING => ItemMatterManipulator.ALLOW_EXCHANGING + case GEOMETRY => 0 + case MOVING => ItemMatterManipulator.ALLOW_MOVING + case CABLES => ItemMatterManipulator.ALLOW_CABLES + } + if (state.hasCap(requiredBit)) { + state.config.placeMode = new_mode + ItemMatterManipulator.setState(stack, state) + result(true) + } + else { + result(false) + } + } + + @Callback(doc = "function(mode: [NONE, REPLACEABLE, ALL]: string) -- Set the remove mode.") + def setRemoveMode(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.removeMode = BlockRemoveMode.valueOf(args.checkString(0)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(mode: [CORNERS, EDGES, FACES, VOLUMES, ALL]: string) -- Set the block select mode.") + def setBlockSelectMode(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.blockSelectMode = BlockSelectMode.valueOf(args.checkString(0)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(action: [MOVING_COORDS, MARK_COPY_A, MARK_COPY_B, MARK_CUT_A, MARK_CUT_B, MARK_PASTE, GEOM_SELECTING_BLOCK, EXCH_SET_TARGET, EXCH_ADD_REPLACE, EXCH_SET_REPLACE, PICK_CABLE, MARK_ARRAY]: string) -- Set the pending action.") + def setPendingAction(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.action = PendingAction.valueOf(args.checkString(0)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(shape: [LINE, CUBE, SPHERE, CYLINDER]: string) -- Set the Shape.") + def setShape(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.shape = Shape.valueOf(args.checkString(0)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- Clear blocks.") + def clearBlocks(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.corners = null + state.config.edges = null + state.config.faces = null + state.config.volumes = null + state.config.action = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(x:number, y:number, z:number) -- Set the coordA.") + def setCoordA(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.coordA = new Location(host.world(), args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(x:number, y:number, z:number) -- Set the coordB.") + def setCoordB(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.coordB = new Location(host.world(), args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(x:number, y:number, z:number) -- Set the coordC.") + def setCoordC(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.coordC = new Location(host.world(), args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- Move here.") + def moveHere(ctx: Context, args: Arguments): Array[AnyRef] = { + if (state.config.shape.requiresC) if (Location.areCompatible(state.config.coordA, state.config.coordB, state.config.coordC)) { + val offsetB = state.config.coordB.toVec.sub(state.config.coordA.toVec) + val offsetC = state.config.coordC.toVec.sub(state.config.coordA.toVec) + val newA = MMUtils.getLookingAtLocation(agent.player()) + val newB = new Vector3i(newA).add(offsetB) + val newC = new Vector3i(newA).add(offsetC) + state.config.coordA = new Location(host.world(), newA) + state.config.coordB = new Location(host.world(), newB) + state.config.coordC = new Location(host.world(), newC) + } + else if (Location.areCompatible(state.config.coordA, state.config.coordB)) { + val offsetB = state.config.coordB.toVec.sub(state.config.coordA.toVec) + val newA = MMUtils.getLookingAtLocation(agent.player()) + val newB = new Vector3i(newA).add(offsetB) + state.config.coordA = new Location(host.world(), newA) + state.config.coordB = new Location(host.world(), newB) + } + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- Clear the coords.") + def clearCoords(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.action = null + state.config.coordA = null + state.config.coordB = null + state.config.coordC = null + state.config.coordAOffset = null + state.config.coordBOffset = null + state.config.coordCOffset = null + ItemMatterManipulator.setState(stack, state) + result(true) + } + + @Callback(doc = "function() -- Clear the transform.") + def clearTransform(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.transform = new Transform + state.config.arraySpan = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- clear whitelist.") + def resetTransform(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.transform = new Transform + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- mark and copy.") + def markCopy(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.action = PendingAction.MARK_COPY_A + state.config.coordA = null + state.config.coordB = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- mark and cut.") + def markCut(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.action = PendingAction.MARK_CUT_A + state.config.coordA = null + state.config.coordB = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- mark and paste.") + def markPaste(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.action = PendingAction.MARK_PASTE + state.config.coordC = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- clear whitelist.") + def clearWhiteList(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.replaceWhitelist = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(x: number, y: number, z: number) -- set array span.") + def setArraySpan(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.arraySpan = new Vector3i(args.checkInteger(0), args.checkInteger(1), args.checkInteger(2)) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function() -- reset array span.") + def resetArraySpan(ctx: Context, args: Arguments): Array[AnyRef] = { + state.config.arraySpan = null + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(flip: ['FLIP_X', 'FLIP_Y', 'FLIP_Z']: string) -- toggle the transform flip.") + def toggleTransformFlip(ctx: Context, args: Arguments): Array[AnyRef] = { + var transform = state.config.transform + if (transform == null) { + transform = new Transform + state.config.transform = transform + } + args.checkString(0) match { + case "FLIP_X" => transform.flipX ^= true + case "FLIP_Y" => transform.flipY ^= true + case "FLIP_Z" => transform.flipZ ^= true + } + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function(side: number, positive: boolean) -- rotate the transform.") + def rotateTransform(ctx: Context, args: Arguments): Array[AnyRef] = { + if (state.config.transform == null) state.config.transform = new Transform + val dir = args.checkInteger(0) + val positive = args.checkBoolean(1) + + if (dir < 0 || dir >= ForgeDirection.VALID_DIRECTIONS.length) return null + val amount = if (positive) 1 else -1 + + var transform = state.config.transform + if (transform == null) { + transform = new Transform + state.config.transform = transform + } + + transform.rotate(ForgeDirection.VALID_DIRECTIONS(dir), amount) + ItemMatterManipulator.setState(stack, state) + null + } + + @Callback(doc = "function():string -- Get the remove mode.") + def getRemoveMode(ctx: Context, args: Arguments) = result(state.config.removeMode.toString) + + @Callback(doc = "function():string -- Get the place mode.") + def getPlaceMode(ctx: Context, args: Arguments) = result(state.config.placeMode.toString) + + @Callback(doc = "function():string -- Get the block select mode.") + def getBlockSelectMode(ctx: Context, args: Arguments) = result(state.config.blockSelectMode.toString) + + @Callback(doc = "function():string -- Get the pending action.") + def getPendingAction(ctx: Context, args: Arguments) = result(Option(state.config.action).map(_.toString).orNull) + + @Callback(doc = "function():string -- Get the current shape.") + def getShape(ctx: Context, args: Arguments) = result(state.config.shape.toString) + + @Callback(doc = "function():table or nil -- Get coordinate A.") + def getCoordA(ctx: Context, args: Arguments) = state.config.coordA + + @Callback(doc = "function():table or nil -- Get coordinate B.") + def getCoordB(ctx: Context, args: Arguments) = state.config.coordB + + @Callback(doc = "function():table or nil -- Get coordinate C.") + def getCoordC(ctx: Context, args: Arguments) = state.config.coordC + + @Callback(doc = "function():string -- Get the replace whitelist.") + def getReplaceWhitelist(ctx: Context, args: Arguments) = result(state.config.replaceWhitelist.toString) + } +} diff --git a/src/main/scala/li/cil/oc/integration/matter_manipulator/ModMatterManipulator.scala b/src/main/scala/li/cil/oc/integration/matter_manipulator/ModMatterManipulator.scala new file mode 100644 index 0000000000..62addc04b9 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/matter_manipulator/ModMatterManipulator.scala @@ -0,0 +1,13 @@ +package li.cil.oc.integration.matter_manipulator + +import li.cil.oc.api.Driver +import li.cil.oc.integration.{ModProxy, Mods} + +object ModMatterManipulator extends ModProxy { + override def getMod = Mods.MatterManipulator + + override def initialize() { + Driver.add(new ConvertMatterManipulator) + Driver.add(new DriverMatterManipulator) + } +} \ No newline at end of file diff --git a/src/main/scala/li/cil/oc/integration/util/MatterManipulator.scala b/src/main/scala/li/cil/oc/integration/util/MatterManipulator.scala new file mode 100644 index 0000000000..ac9b3edb22 --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/util/MatterManipulator.scala @@ -0,0 +1,26 @@ +package li.cil.oc.integration.util + +import li.cil.oc.integration.Mods +import net.minecraft.item.ItemStack +import com.recursive_pineapple.matter_manipulator.common.items.manipulator.ItemMatterManipulator +import com.recursive_pineapple.matter_manipulator.common.items.MMUpgrades +import com.recursive_pineapple.matter_manipulator.common.items.manipulator.MMState.PlaceMode + +object MatterManipulator { + + def isMatterManipulator(stack: ItemStack) = + stack != null && stack.stackSize > 0 && + Mods.MatterManipulator.isAvailable && + stack.getItem.isInstanceOf[ItemMatterManipulator] + + def getPlaceTicks(stack: ItemStack) = + stack.getItem match { + case item_mm : ItemMatterManipulator => { + var placeTicks = item_mm.tier.placeTicks + var state = ItemMatterManipulator.getState(stack) + if (state.hasUpgrade(MMUpgrades.Speed)) placeTicks = placeTicks / 2 + placeTicks + } + case _ => 0 + } +} diff --git a/src/main/scala/li/cil/oc/server/agent/Player.scala b/src/main/scala/li/cil/oc/server/agent/Player.scala index faada23a47..3412f6fc8f 100644 --- a/src/main/scala/li/cil/oc/server/agent/Player.scala +++ b/src/main/scala/li/cil/oc/server/agent/Player.scala @@ -1,7 +1,6 @@ package li.cil.oc.server.agent import java.util.UUID - import com.mojang.authlib.GameProfile import cpw.mods.fml.common.ObfuscationReflectionHelper import cpw.mods.fml.common.eventhandler.Event @@ -14,7 +13,7 @@ import li.cil.oc.common.EventHandler import li.cil.oc.integration.Mods import li.cil.oc.integration.magtools.ModMagnanimousTools import li.cil.oc.integration.tcon.ModTinkersConstruct -import li.cil.oc.integration.util.PortalGun +import li.cil.oc.integration.util.{MatterManipulator, PortalGun} import li.cil.oc.util.BlockPosition import li.cil.oc.util.InventoryUtils import net.minecraft.block.Block @@ -29,7 +28,7 @@ import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer.EnumStatus import net.minecraft.init.Blocks import net.minecraft.init.Items -import net.minecraft.inventory.{IInventory, ContainerPlayer} +import net.minecraft.inventory.{ContainerPlayer, IInventory} import net.minecraft.item.ItemBlock import net.minecraft.item.ItemStack import net.minecraft.network.NetHandlerPlayServer @@ -283,6 +282,10 @@ class Player(val agent: internal.Agent) extends FakePlayer(agent.world.asInstanc posY += offset.offsetY * 0.6 posZ += offset.offsetZ * 0.6 val newStack = stack.useItemRightClick(world, this) + if (MatterManipulator.isMatterManipulator(stack)) { + newStack.getItem.onUsingTick(newStack, this, Integer.MAX_VALUE - 1) + newStack.getItem.onUsingTick(newStack, this, Integer.MAX_VALUE - MatterManipulator.getPlaceTicks(stack) * 10) + } if (isUsingItem) { val remaining = customItemInUseBecauseMinecraftIsBloodyStupidAndMakesRandomMethodsClientSided.getMaxItemUseDuration - heldTicks customItemInUseBecauseMinecraftIsBloodyStupidAndMakesRandomMethodsClientSided.onPlayerStoppedUsing(world, this, remaining) From a75827b85d10d266fa82311bde165183362c45af Mon Sep 17 00:00:00 2001 From: hinyb <40139991+hinyb@users.noreply.github.com> Date: Tue, 16 Dec 2025 14:13:37 +0800 Subject: [PATCH 2/2] Fix: Correct return type for getCoord --- .../matter_manipulator/DriverMatterManipulator.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala b/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala index 19270d939c..bf1b7ba160 100644 --- a/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala +++ b/src/main/scala/li/cil/oc/integration/matter_manipulator/DriverMatterManipulator.scala @@ -261,13 +261,13 @@ class DriverMatterManipulator extends DriverItem { def getShape(ctx: Context, args: Arguments) = result(state.config.shape.toString) @Callback(doc = "function():table or nil -- Get coordinate A.") - def getCoordA(ctx: Context, args: Arguments) = state.config.coordA + def getCoordA(ctx: Context, args: Arguments) = result(state.config.coordA) @Callback(doc = "function():table or nil -- Get coordinate B.") - def getCoordB(ctx: Context, args: Arguments) = state.config.coordB + def getCoordB(ctx: Context, args: Arguments) = result(state.config.coordB) @Callback(doc = "function():table or nil -- Get coordinate C.") - def getCoordC(ctx: Context, args: Arguments) = state.config.coordC + def getCoordC(ctx: Context, args: Arguments) = result(state.config.coordC) @Callback(doc = "function():string -- Get the replace whitelist.") def getReplaceWhitelist(ctx: Context, args: Arguments) = result(state.config.replaceWhitelist.toString)