battlecode-server-2017
battlecode-server-2017 copied to clipboard
Can't use BodyInfo in Scrimmage
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.
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
.
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)
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