robocode-dev / robocode-api-bridge

Bridge for the original Robocode API to run original Robocode robots on Tank Royale
Apache License 2.0
2 stars 0 forks source link

Wrapped bot throws exception #1

Open Cu3PO42 opened 5 days ago

Cu3PO42 commented 5 days ago

Hi! I'd like to start by thanking you for your continued work on Robocode. I've had a lot of fun with it for almost a decade now.

While evaluating the new Tank Royale platform, I attempted to port some legacy (non-publically-available) bots using the API bridge. They all trigger the same exception at runtime:

dev.robocode.tankroyale.botapi.BotException: StatusEventMapper.map: Could not get robot status from map
    at dev.robocode.tankroyale.bridge.StatusEventMapper.map(StatusEventMapper.java:14)
    at dev.robocode.tankroyale.bridge.AllEventsMapper.lambda$map$0(AllEventsMapper.java:28)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at dev.robocode.tankroyale.bridge.AllEventsMapper.map(AllEventsMapper.java:21)
    at dev.robocode.tankroyale.bridge.BotPeer.getAllEvents(BotPeer.java:535)
    at dev.robocode.tankroyale.bridge.BotPeer.getScannedRobotEvents(BotPeer.java:613)
    at robocode.AdvancedRobot.getScannedRobotEvents(AdvancedRobot.java:889)
    at infovk.repro.TankRoyaleRepro.getScannedRobotEvents_(TankRoyaleRepro.java:34)
    at infovk.repro.TankRoyaleRepro.act(TankRoyaleRepro.java:72)
    at infovk.repro.TankRoyaleRepro.run(TankRoyaleRepro.java:51)
    at dev.robocode.tankroyale.bridge.BotPeer$BotImpl.runRobot(BotPeer.java:732)
    at dev.robocode.tankroyale.bridge.BotPeer$BotImpl.run(BotPeer.java:721)
    at dev.robocode.tankroyale.botapi.internal.BotInternals.lambda$startThread$3(BotInternals.java:118)
    at java.base/java.lang.Thread.run(Thread.java:1583)

I have tried to create a minimal reproducing sample bot that triggers the behavior and am attaching a packaged jar. You can find the source in this gist. The bot is expected to do nothing except maintain a radar lock in a 1v1, it neither moves nor fires.

The issue seems to stem from requesting the robot's event queue, but not to be related to ScannedRobotEvents specifically. In the "full framework", we handle all event types, but this does not seem to trigger any additional errors.

The reason for the admittedly somewhat odd event handling is that this is the above example is the result of taking a framework and stripping away everything that was not needed to trigger the exception. (Background Info: At my university, the stundents organize a one week introductory programming course for new students before actual classes start. We've found that event handlers were a difficult concept to grasp for many, so we wanted to move everything into the main loop and are storing events in a queue. It's been a few years since I wrote those abstractions, so I unfortunately do not recall why we have our own queue, but also reference AdvancedRobot#getScannedRobotEvent.)

Everything works on legacy Robocode and I'm decently confident we're not violating any laws of Robocode, but I wouldn't guarantee it 100%. I have done my best to strip down everything that is not needed to reproduce the issue.

Thank you in advance for looking into this!

flemming-n-larsen commented 5 days ago

@Cu3PO42

I am happy to hear that you have had a lot of fun with Robocode! 😊

And thank you for both reporting the issue, and providing a lot of details for how to reproduce it, which is crucial for getting the issues fixed. It sounds like a generic bug with the bridge that needs to be fixed.

Regarding not using event handler, and instead using the main loop and reading out events from there is a perfectly legal way to do it in Robocode. You can use the event handlers, if you want, or just extract the current events from the main method or any other method.

I will have a look into this issue and see if I can fix it. πŸ™‚

flemming-n-larsen commented 3 days ago

@Cu3PO42

I have now fixed the issue in the (robocode-api) causing the issue you encountered. And the TankRoyaleRepro you provided seems to run fine with the fixed version. :+1:

I have put the new robocode-api-0.2.0.jar for you here into a zip file (GitHub does not allow me to upload jar files directly) robocode-api-0.2.0.zip

If you encounter more issues, if will be very happy if you raise more tickets about it so we can improve the bridge and be able to support as many legacy robots as possible. 😊

Cu3PO42 commented 3 days ago

Thanks for getting to this so quickly! I can confirm the reproduction bot now runs correctly in the first round, and so do other bots based on the same framework.

Unfortunately, they all stop working in the second round due to issues I suspect are related. I'll open another issue when I have the time to do a proper write up for this (probably tomorrow).


The reproduction bot I included fails with the exception

java.util.ConcurrentModificationException
    at java.base/java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1253)
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at infovk.repro.TankRoyaleRepro.getScannedRobotEvents_(TankRoyaleRepro.java:35)
    at infovk.repro.TankRoyaleRepro.run(TankRoyaleRepro.java:49)
    at dev.robocode.tankroyale.bridge.BotPeer$BotImpl.runRobot(BotPeer.java:729)
    at dev.robocode.tankroyale.bridge.BotPeer$BotImpl.run(BotPeer.java:718)
    at dev.robocode.tankroyale.botapi.internal.BotInternals.lambda$startThread$3(BotInternals.java:118)
    at java.base/java.lang.Thread.run(Thread.java:1583)
java.util.ConcurrentModificationException
    at java.base/java.util.LinkedList$LLSpliterator.forEachRemaining(LinkedList.java:1253)
    at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682)
    at infovk.repro.TankRoyaleRepro.getScannedRobotEvents_(TankRoyaleRepro.java:35)
    at infovk.repro.TankRoyaleRepro.run(TankRoyaleRepro.java:49)
    at dev.robocode.tankroyale.bridge.BotPeer$BotImpl.runRobot(BotPeer.java:729)
    at dev.robocode.tankroyale.bridge.BotPeer$BotImpl.run(BotPeer.java:718)
    at dev.robocode.tankroyale.botapi.internal.BotInternals.lambda$startThread$3(BotInternals.java:118)
    at java.base/java.lang.Thread.run(Thread.java:1583)

Other bots fail with

The thread of the bot could not be interrupted causing the bot to hang.
So the bot was stopped by force.

I assume the thread running the bot for the first round keeps running even after it is complete. This seems to align with the infinite main-loop. Might it be necessary to throw some termination exception? I'll need to look into how that currently work.

flemming-n-larsen commented 3 days ago

@Cu3PO42

Let us continue on this thread with the second issue as well. πŸ™‚

A ConcurrentModificationException should be easy to fix as soon as I figure out where it happens. I will have a look at this as well.

Cu3PO42 commented 2 days ago

Sure, if that works better for you I'm happy to continue here! I have been able to create a simple reproduction for the other exception

The thread of the bot could not be interrupted causing the bot to hang.
So the bot was stopped by force.

as well.

Compared to the previous version, I have added basic linear targeting. You can find the source here and a packaged version in this ZIP.

I suspect that the actual implementation of linear targeting is irrelevant and the different error is simply caused by slightly different timing.

flemming-n-larsen commented 1 day ago

@Cu3PO42

I have already found several issues that I am trying to solve within the Bot APIs for Java and C#. The most critical one is the one you already mentioned, that it seems that old threads are not stopping in new rounds. And another where the bridged bots cannot be restarted as they disconnect from the WebSocket and exits.