Logistics Pipes

Logistics Pipes

13M Downloads

OpenComputers support?

LizzyTrickster opened this issue · 23 comments

commented

It'd be nice to see OC support as well as CC because I want to automate tasks with LP using OC but I can't because there is little to no comparability (I also don't use CC)

commented

Documentation at https://github.com/MightyPirates/OpenComputers/tree/master/src/main/java/li/cil/oc/api seems to show that a minimal integratrion isn't complex

commented

A minimal integratrion might not be complex but it would probably only consist of a get pipe type method so nothing usefull. Everything else inside LP's CC interaction is now object based and I don't see a way to integrate that into OC. I don't know scala so I can't just look into the code and I can't find anything equal to the ILuaObject from CC in the API. I'm not willing to add a complete new method set for OC computers. So unless someone finds a way to integrate the object based way LP uses with CC now, I don't think there will be an OC integration.

commented
commented

In OC 1.2 it's indeed impossible to push objects (or 'userdata' as it's called in Lua lingo). In 1.3 that is possible, however. I think I just tracked down the last show-stopper bug, so I'll probably release an RC later today, and the 1.3 API has been stable for a while now, so there should be no concerns on that end.

There are a few minor differences to CC's ILuaObject, though:

  • Callbacks in OC userdata cannot yield / pull events. This is a necessary limitation to allow the computers' persistence (can't have Java calls in the callstack for that).
  • OC userdata (Value interface) have callbacks for most of Lua's "metamethods", i.e. they can be used to simulate arrays / maps, functions, etc. Declaration of callbacks works as it does for components, i.e. using methods annotated using the @Callback annotation or, in this case probably more appropriate - because for the most part compatible with CC's format (see PS) - by additionally implementing the ManagedPeripheral interface.
  • OC userdata must be persistable - it is saved together with the computer it was pushed into. That is, the class must have a default constructor for loading.

I have implemented some wrapper logic in OpenComponents as somewhat of a test-case, encapsulating CC's ILuaObjects, which seems to work well - except for stuff that wants to yield, of course, and the objects become unusable after loading. Point being, it's possible that with the newest OpenComponents, LP next to an Adapter even works out-of-the box (until saving and loading again at least). With the limitation that CC+OP also have to be present, of course.

If you need any more information, I'm happy to assist!

PS: regarding the 'for the most part' bit, there's a slight pit-fall when extracting OC's arguments using Argument.checkAny: since for Lua strings are just byte arrays, that's what you'd get for strings passed by Lua from checkAny (whereas they're auto converted to strings in checkString). Just for reference.

commented

Do you have any precompiled dev versions I can use in my IDE to work with?

commented

Aye, there are dev builds, including deobf ones over on my Jenkins.

commented

Ah thanks.

commented

OK. Got most of the stuff working now. Nearly everything is now persistable. But the one thing I can't get to work is using the objects as arguments for methods. Whenever I try to use checkAny, I get an Map Containing the method names, and an entry "type" with the value "userdata".
The Object is successfully pushed to lua as a raw value and if I check it in that moment it is correctly returned as raw java object. But for whatever reason when a method is called with this object as an argument it isn't the object itself but the map representing it that is used as argument.

Map:
help : class com.naef.jnlua.DefaultConverter$18
type : userdata
toString : class com.naef.jnlua.DefaultConverter$18
helpCommand : class com.naef.jnlua.DefaultConverter$18
identify : class com.naef.jnlua.DefaultConverter$18
getItemIdentifierBuilder : class com.naef.jnlua.DefaultConverter$18

It's an AbstractTableMap.
help, helpCommand, toString, identify, and getItemIdentifierBuidler are methods of the object in question.
The object extens AbstractValue and uses @Callback annotations to define methods in the class and in a subclass. I've got a workaround in mind but that wouldn't be nice and would probably lead to confusion on the user's side.

Edit: Is there anything like a toString function that can be defined to tell lua what to display when =object is used?

commented

Ah, that sounds like I don't "unwrap" the userdata somewhere when it's passed back to Java. I'll look into it right now!

As for tostring, not yet, I could add that, though.

commented

'Must be persistable' at the moment we garbage collect and potentially
re-use the object class for item id. If OpenComputers saves it and doesn't
keep a copy of the Java object, we will need a sanity check + recompute of
the I'd for each I'd passed back to us, also, because of this we don't have
a serialise/deserialise capability for our ItemIdentifier class
On 4 Jul 2014 21:51, "Florian Nücke" [email protected] wrote:

In OC 1.2 it's indeed impossible to push objects (or 'userdata' as it's
called in Lua lingo). In 1.3 that is possible, however. I think I just
tracked down the last show-stopper bug, so I'll probably release an RC
later today, and the 1.3 API has been stable for a while now, so there
should be no concerns on that end.

There are a few minor differences to CC's ILuaObject, though:

I have implemented some wrapper logic in OpenComponents as somewhat of a
test-case, encapsulating CC's ILuaObjects, which seems to work well -
except for stuff that wants to yield, of course, and the objects become
unusable after loading. Point being, it's possible that with the newest
OpenComponents, LP next to an Adapter even works out-of-the box (until
saving and loading again at least). With the limitation that CC+OP also
have to be present, of course.

If you need any more information, I'm happy to assist!


Reply to this email directly or view it on GitHub
#397 (comment)
.

commented

Hmm, if you need to keep object references to things that get saved to somewhere else, things will get... complicated, yes. If that gets too messy, it might even be better to load into a deliberately invalid state and error when the object is accessed, so Lua programs know they have to re-acquire the objects (please do not error while loading, else the complete computer state fails to load).

commented

Hmm, somehow I can't reproduce it. Just to make sure I got it right:

  • You have your Value implementation.
  • You pass it to Lua.
  • From Lua you call some other method and pass that value along.
  • On the Java side it's then a table representation, not the actual object anymore.

I tried it "directly" and across leaving and loading the world again, either worked fine. I do remember fixing something userdata related one of the last days, though. Could you check if it's still happening in the latest build? Thanks!

commented

Ahhh, I found it, in my testcase the callback wasn't direct, so that's where the missing unwrap was hiding. It's fixed in build 496! Sorry about that, and thanks for making me aware of the bug :-)

As for the classes being dynamically created, the only case where this matters (well, that I can think of) is when the objects are unpersisted. The actual instances are re-created using the class name. The actual save and load logic can be seen here. If the generated classes are known to the class loader at the time the world is loaded it would work, I guess?

commented

As the class is injected through a class transformer it can be loaded by the persistance code (Tested).
Will test the new build tomorro. Thanks for the fix.

commented

I think the object we pass has enough data to re-create the original item,
so it should be possible to
a) check if the ItemID has changed due to cleanup during de-serialisation,
b) create an item of the correct type, then look up the correct ID for it.
This may mean that on de-serializatation, followed by immediate
serialization will produce different results, but i think it may be
possible to handle this situation without "issues".

IId's store a) a unique integer for each different item (if it is possible
for a <> b then they have a different ID) normal comparison between IID
just use this int.
they also store the NBT for an item of that type, so assuming the IID
serializes the nbt, then we can recreate the item even if the integer id is
wrong.

On Mon, Jul 7, 2014 at 8:30 AM, Florian Nücke [email protected]
wrote:

Hmm, if you need to keep object references to things that get saved to
somewhere else, things will get... complicated, yes. If that gets too
messy, it might even be better to load into a deliberately invalid state
and error when the object is accessed, so Lua programs know they have to
re-acquire the objects (please do not error while loading, else the
complete computer state fails to load).


Reply to this email directly or view it on GitHub
#397 (comment)
.

“Getting information off the Internet is like taking a drink from a fire
hydrant.”
– Mitchell Kapor

commented

Yup, to add a bit: pretty much the only visible thing the internal uniqueID assignment affects is sort order between items with identical ID:meta but different NBT (assuming no one is doing silly things like comparing object identity instead of using .equals()).
e.g. if we create 2 ItemIdentifiers A and B from from id:dmg:nbtA and id:dmg:nbtB, we get A.compareTo(B) < 0. Drop all references to them, create them again, now A.compareTo(B) can be >0.
The question is if this particular quirk could become a problem here.

commented

what if we sort by nbt hash as last fallback?

On Mon, Jul 7, 2014 at 10:15 AM, ArtForz [email protected] wrote:

Yup, to add a bit: pretty much the only visible thing the internal
uniqueID assignment affects is sort order between items with identical
ID:meta but different NBT (assuming no one is doing silly things like
comparing object identity instead of using .equals()).
e.g. if we create 2 ItemIdentifiers A and B from from id:dmg:nbtA and
id:dmg:nbtB, we get A.compareTo(B) < 0. Drop all references to them, create
them again, now A.compareTo(B) can be >0.
The question is if this particular quirk could become a problem here.


Reply to this email directly or view it on GitHub
#397 (comment)
.

“Getting information off the Internet is like taking a drink from a fire
hydrant.”
– Mitchell Kapor

commented

I was actually considering doing that and only falling back to uniqueID when we get a collision on tag.hashCode() for non-equal NBT.
Problem is, that still has the same non-guaranteed ordering issue, it just massively reduces the chance of it ever being encountered.
If we really need persistent ordering, we'll have to implement a comparator for NBT tags as a tie breaker there (which shouldn't need to be particularly efficient, this should only happen very rarely).

commented

@AartBluestoke here is how that stuff is persistable: BaseWrapperClass

@fnuecke Our wrapper extends the AbstractValue class: BaseWrapperClass
I downloaded the newest build I could find OpenComputers-MC1.6.4-1.3.0.490-rc.1-deobf.jar.
Methods are declared like this:
DummyWrapperClass
And if i then do this:
BaseWrapperClass
I get the Map into my array and show that here: LPGlobalCCAccess
(There is still debug code in there so ignore stuff like the Seq<Object> base = ((ArgumentsImpl)args).args();)
When the value is pushed to the lua stack it's correct but when it is read from it again it seems to be read as the map.
Do you need access to the byteCode of classes when they are stored inside lua? The wrapper is generated by ASM. Could that cause an issue with the native code?
ASM code: ClassCreator
That's the layout a created class will look like: DummyWrapperClass

commented

OK, that did work, Thanks.
Is there any way to block the oc network construction over several connected pipes. Currentlly when I connect several LP pipes together and there are computers on either side they link over the conected LP pipes (Monitor on one end with PC on the other end)

commented

Good to hear!

You can add the SidedEnvironment interface to control on which sides connections are possible. For example, check if the block on the requested side is a pipe, if so return null, else return the node.

commented

OK support is in. Thanks for the help @fnuecke.

commented

Awesome :-)