battlecode-server-2017 icon indicating copy to clipboard operation
battlecode-server-2017 copied to clipboard

Can't use BodyInfo in Scrimmage

Open revalo opened this issue 8 years ago • 3 comments

battlecode.instrumenter.InstrumentationException: ILLEGAL Illegal class: battlecode/schema/BodyType
    this class cannot be referenced by player code.

Can't use Polymorphism.

Edit: mistake in title.

revalo avatar Jan 15 '17 04:01 revalo

Why do you need BodyType? Player code can only rely on battlecode/common, you shouldn't need anything in battlecode/schema.

As far as polymorphishm goes, Robotinfo, BulletInfo, and TreeInfo all implement BodyInfo.

Pear0 avatar Jan 16 '17 20:01 Pear0

This really needs to be solved ASAP, as it really slows down the development process.

Polymorphism in general works as this example shows:

def testPolymorphism[T](array: Array[T]): Boolean = true

def minimalExample() = {
   val trees: Array[TreeInfo] = rc.senseNearbyTrees()
   assert(testPolymorphism(array)))
   // No exception whatsoever
}

But there is something wrong as this example shows:

def minimalExample() = {
   System.out.println(
      rc.senseNearbyTrees() ++  rc.senseNearbyRobots() // InstrumentationException!
   )
   // This also throws an exception
   (rc.senseNearbyTrees(): Array[BodyInfo]) ++ (rc.senseNearbyRobots(): Array[BodyInfo])
   // The following work fine
   (rc.senseNearbyTrees(): Array[TreeInfo]) ++ (rc.senseNearbyRobots(): Array[TreeInfo])
   (rc.senseNearbyTrees(): Seq[BodyInfo]) ++ (rc.senseNearbyRobots(): Seq[BodyInfo])   
}

Running it results in this stack trace:

Stack trace: 
battlecode.instrumenter.InstrumentationException: ILLEGAL Illegal class: scala/reflect/ClassTag$
    this class cannot be referenced by player code.
        at battlecode.instrumenter.bytecode.ClassReferenceUtil.classReference(ClassReferenceUtil.java:172)
        at battlecode.instrumenter.bytecode.InstrumentingMethodVisitor.classReference(InstrumentingMethodVisitor.java:78)
        at battlecode.instrumenter.bytecode.InstrumentingMethodVisitor.visitFieldInsnNode(InstrumentingMethodVisitor.java:251)
        at battlecode.instrumenter.bytecode.InstrumentingMethodVisitor.visitMaxs(InstrumentingMethodVisitor.java:108)
        at org.objectweb.asm.ClassReader.a(Unknown Source)
        at org.objectweb.asm.ClassReader.b(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at org.objectweb.asm.ClassReader.accept(Unknown Source)
        at battlecode.instrumenter.TeamClassLoaderFactory$Loader.instrument(TeamClassLoaderFactory.java:522)
        at battlecode.instrumenter.TeamClassLoaderFactory$Loader.loadClass(TeamClassLoaderFactory.java:443)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

omelkonian avatar Jan 16 '17 20:01 omelkonian

These are really two separate issues.

For @revalo's issue:

Make sure your code doesn't rely on (even import) any battlecode code that isn't in battlecode/common.

For @omelkonian's issue:

To fix this, the devs need to whitelist scala/reflect/ClassTag$ and possibly scala/reflect/ClassTag, but as a workaround, you can convert to any other collection and it should work just fine:

object RobotPlayer {
  def run(rc: RobotController) {
    
    val things = rc.senseNearbyRobots().toList ++ rc.senseNearbyTrees().toList // this works

    println(things)
  }
}

Explanation:

For historical reasons, all container types except arrays undergo type erasure. A side effect of this is that in Java, generic arrays new E[] cannot be instantiated while other containers can. Scala gets around that by using ClassTag objects which store the Class object and can use reflection to instantiate new arrays of a generic type.

Edit: reformatted some things

Pear0 avatar Jan 17 '17 00:01 Pear0