Queue full
I´m writing a custom client right now (slowly writing it from scratch in the last months). Yesterday I managed to make it fully functional, although it still needs polishing (make hardcoded behaviour more configurable). I´ll make it available here after it becomes more stable.
I can add bulk upload, but it will break compatibility with the current protocol. Unless both clients and servers support 2 protocols at the same time.
Features I managed to include in this custom client so far:
- Full compatibility with the current protocol. (I hope that underscore bug was the last one)
- Multiprocess/multithread support.
- Parallel downloading of JARs. (currently hardcoded at 15 simultaneous downloads)
- Processing battles in parallel while uploading results in a separate process. (currently hardcoded at 1 simultaneous upload)
- Abusing the Java 5 concurrent API to keep the code readable in the presence of parallelism.
- Upload throttling in case of errors (currently hardcoded at 10 seconds delay after each error). It is possible to throttle uploads in the absence of errors too, although I wasn´t planning to do that.
- Smarter handling of priority battles. One big pairing matrix handles priority battles, new competitors and competitors with low battle count, all at the same time. And it is independent from iterations (which I eliminated).
- Communication between processes through the network, allowing clients spread accross a LAN. (currently hardcoded at "localhost" address and 1099 port only)
- Automatic copying of JARs between clients. If a single "server" process has all JARs, no client needs to download from internet.
- Logging support. No more System.out.println. You can configure how messages appear in the console (or in a file), adding for example, time and severity.
- Internally, battle parameters are all dynamic. Parameters like number of competitors, inactivity time, gun heat cooldown, codesize classes, hideRobotNames, are all concentrated in a configuration class. The idea is to put them all in configuration files and make divisions like twin duel, team melee or anything else fully supported.
Neat! Sounds like a lot of work. What's the setup like for multi-process battles? And is it the same mechanism locally vs clients across a network?
There is a "server" process and multiple "worker" processes. You start the server process by calling server.cmd. And start each worker process by calling worker.cmd. Each one runs in a separate JVM and needs its own Robocode installation. This way each process runs in a separate window and you can see what each is doing.
All communication to LiteRumble is done by the server process alone. Server and workers communicate through RMI.
Server process is currently using the same configuration file of the official client. Worker processes are currently 100% hardcoded, but server address/port and robocode home could be configured.
Server process downloads participants list, ratings, download JARs (in a separate "jar" thread-pool), calculate codesize, remove old participants and generate a local participants list. They run in a "download" single-thread pool (except jars). Participants list and battle count are sent to a "battle generation" thread-pool, which is single-threaded.
Worker processes connect to the server and requests a battle, which is generated on-the-fly by the server in the "battle generation" thread pool. Then the worker runs the battle and sends the result back to the server. Worker processes are mono-threaded (except for threads internal to Robocode).
Server receives the result, splits it in codesize classes and sends them to an "upload" thread pool, which is currently single-threaded.
In the "upload" thread pool, results are uploaded to LiteRumble. Battle count and priority battles are downloaded and sent to the "battle generation" thread pool. If workers flood the "upload" thread pool with results, upload requests are kept in a queue, and are uploaded one at a time.
In the battle generator, participants list, battle count and priority battles are grouped and used to generate a smart battle whenever a worker requests. All battle generation logic is kept in a single class, in a single thread, making it easy to customize.
The result is you see battles going non-stop on workers, and uploads going almost non-stop in the server process, one at a time. Makes a huge difference in melee.