-
Notifications
You must be signed in to change notification settings - Fork 6
Home
Documentation about the protocols is available here!
No, but I'd recommend you to copy the whole thing first and then delete the stuff you don't need. Some libraries depend on others, so check out the #include
s below the big comment at the top of the file. All of them require _link_common.hpp
.
Most libraries provide activate()
and deactivate()
methods. You must only enable one at a time!
If you are using library A and want to switch to library B, do the following:
- Call
deactivate()
on A. - Disable all the interrupt handlers you've added.
- Add all the required interrupt handlers of B, if needed.
- Call
activate()
on B.
When these methods aren't available, look for a reset()
method. If there isn't one, the library just resets itself after usage.
The interrupt handler provided by libtonc has a bug where it sometimes misses interrupts. I'd recommend using the one in libugba, like gba-link-connection examples do.
How do I use these libraries with the Butano engine?
Check out the LinkUniversal_real example code, which uses Butano 18.8.0.
Note that the engine already has an integrated multiplayer handler based on an old version of πΎ LinkCable.
To prevent livelocks in their protocols, mostly. You can set your own RNG seed in Link::randomSeed
.
This library alternates between Link Cable and Wireless Adapter modes to achieve a working connection as fast as possible. When using the Wireless Adapter, it automatically handles the room creation with a simple autopairing logic, so users don't have to 'host' or 'join' rooms.
Well, you can implement a room list and host/join logic in your game using π» LinkWireless. Then, if you prefer to continue using π LinkUniversal, you can switch to it:
linkWireless->deactivate(false); // (false = don't turn off the adapter)
// disable LinkWireless ISRs here
// enable LinkUniversal ISRs here
linkUniversal->setProtocol(LinkUniversal::Protocol::WIRELESS_RESTORE_EXISTING);
linkUniversal->activate();
do { linkUniversal->sync() } while (!linkUniversal->isConnected());
The library provides the getLinkCable()
and getLinkWireless()
methods to retrieve the internal instances. Use responsibly! You can break everything!
Because πΎ LinkCable doesn't allow it, and if I allowed it here, it wouldn't be so Universal, right? That said, you can always use getLinkWireless()->send(...)
and send any 16-bit word in wireless mode.
You shouldn't, so please check:
- that your interrupt handler doesn't miss interrupts.
- that
LINK_CABLE_ISR_SERIAL
is called on time, when using a Link Cable, since it's time-sensitive. That means, be careful with DMA usage (which stops the CPU), and write short interrupt handlers. Alternatively, you can activate nested interrupts by settingREG_IME=1
at the start of your handlers, but beware of race conditions! - that the
retransmission
option is enabled, when using a Wireless Adapter. - that you empty your message queue (aka
canRead()
returnsfalse
) before every newsync()
call. - that
LINK_CABLE_QUEUE_SIZE
andLINK_WIRELESS_QUEUE_SIZE
are large enough. - that the return value of
didQueueOverflow()
is alwaysfalse
. If true, it means the internal queue lost messages at some point.
- πΎ LinkCable shouldn't eat too much CPU (like ~5%) in any normal usages.
- π» LinkWireless, in its default configuration, takes ~5% when placing ISR code in IWRAM and ~10% when in ROM, though this depends on a lot of factors like send interval, number of players, retransmission/forwarding options, etc.
You can use the LinkUniversal_stress.gba
and LinkWireless_prof_*.gba
roms to check the total cycles consumed by ISRs per frame.
These compile-time constants could affect performance significantly:
LINK_WIRELESS_PUT_ISR_IN_IWRAM_*
LINK_WIRELESS_MAX_SERVER_TRANSFER_LENGTH
If the room reaches its maximum number of allowed players, this is done automatically. If you want to implement a screen where players join the room waiting for others until everyone is ready, and then close the server, you can do it by calling closeServer()
.
By design, if a player disconnects, the room is closed. The hardware allows it though, since it has a slot system where -for example- players 2
and 4
can be connected but 3
is offline, but you'd have to implement it yourself using π§π» LinkRawWireless (and lose most of the features that π» LinkWireless handles for you like retransmission, or forwarding).
π LinkUniversal's autopairing can be very handy here, but keep in mind that player IDs are not preserved, so you need to build a system where each player has a sticky ID, independent from the assigned hardware ID.
The sync version is simpler (with one method call you can send the whole ROM and get the result), but blocks the system until completion. It also uses the MultiBoot SWI, which prevents music from being played easily since it requires DMA to be disabled. The async version is what games probably want: it's slower, but allows animations and music to be played.
Check out the LinkUniversal_real example code.
Both sync and async versions of the library have a keepConnectionAlive
configuration option that keeps the Wireless Adapter alive after the transfer is completed. Then, when the others boot the received ROM, they can call linkWireless->restoreExistingConnection()
to initialize π» LinkWireless from the existing connection. The same is possible in π LinkUniversal using the LinkUniversal::Protocol::WIRELESS_RESTORE_EXISTING
protocol.
Remember that the other consoles need some time to boot the game, so it's recommended to use high timeouts at first. Once everyone sends messages indicating they are alive, you can set a tighter timeout with linkWireless->config.timeout
and call linkWireless->resetTimeout()
.