Skip to content
Merged

Dev #55

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

Expand Down
17 changes: 7 additions & 10 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,16 @@ on:
types: [published]

jobs:
build-and-release:
build:
runs-on: ubuntu-latest

permissions:
contents: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
- uses: actions/checkout@v4

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
java-version: '25'
distribution: 'temurin'
cache: gradle

Expand All @@ -31,9 +27,10 @@ jobs:
- name: Build with Gradle
run: ./gradlew deploy

- name: Upload JARs to GitHub Release
uses: softprops/action-gh-release@v2
- name: Upload build artifact
uses: actions/upload-artifact@v4
with:
files: build/libs/*.jar
name: scheme-size-port-build
path: build/libs/*.jar
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6 changes: 3 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ plugins {
version = '1.0'

java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_25
targetCompatibility = JavaVersion.VERSION_21
}

configurations.matching { it.canBeResolved }.configureEach {
Expand Down Expand Up @@ -40,7 +40,7 @@ ext {
}

tasks.withType(JavaCompile).configureEach {
options.compilerArgs.addAll(['--release', '8'])
options.compilerArgs.addAll(['--release', '21'])
}


Expand Down
2 changes: 1 addition & 1 deletion mod.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ author: '''
Port: 00SunRay00 & RE2b2m22
'''
minGameVersion: 159
version: 2.2.0
version: 2.2.5
hidden: true
main: scheme.Main
6 changes: 3 additions & 3 deletions src/java/api/src/com/xpdustry/claj/api/Claj.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import arc.struct.Seq;

import com.xpdustry.claj.common.ClajPackets;
import com.xpdustry.claj.common.packets.ConnectionPacketWrapPacket;
import com.xpdustry.claj.common.packets.ConnectionPayloadPacket;
import com.xpdustry.claj.common.status.*;


Expand All @@ -47,15 +47,15 @@ public static Claj init(ClajProvider provider) {
}

/**
* Initializes the global CLaJ manager, and the {@link ConnectionPacketWrapPacket} serializer.
* Initializes the global CLaJ manager, and the {@link ConnectionPayloadPacket} serializer.
* @param provider the implementation specific things
* @param proxies number of pooled proxies
* @param pingers number of pooled pingers
*/
public static Claj init(ClajProvider provider, int proxies, int pingers) {
if (initialized()) throw new IllegalStateException("Claj is already initialized");
ClajPackets.init(); // Register packets first
ConnectionPacketWrapPacket.serializer = provider.getPacketWrapperSerializer();
ConnectionPayloadPacket.serializer = provider.getPacketWrapperSerializer();
INSTANCE = new Claj(provider, new ClajProxyManager(provider, proxies),
new ClajPingerManager(provider, pingers));
return INSTANCE;
Expand Down
77 changes: 33 additions & 44 deletions src/java/api/src/com/xpdustry/claj/api/ClajClientSerializer.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/**
* This file is part of CLaJ. The system that allows you to play with your friends,
* just by creating a room, copying the link and sending it to your friends.
* Copyright (c) 2025-2026 Xpdustry
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.xpdustry.claj.api;

import java.nio.ByteBuffer;
Expand All @@ -14,78 +33,48 @@
import com.xpdustry.claj.common.packets.Packet;
import com.xpdustry.claj.common.packets.RawPacket;

public class ClajClientSerializer implements NetSerializer, FrameworkSerializer {

public class ClajClientSerializer implements NetSerializer, FrameworkSerializer {
protected final ThreadLocal<ByteBufferInput> read = Threads.local(ByteBufferInput::new);
protected final ThreadLocal<ByteBufferOutput> write = Threads.local(ByteBufferOutput::new);

@Override
public Object read(ByteBuffer buffer) {
if (!buffer.hasRemaining()) return null;

return switch (buffer.get()) {
byte id = buffer.get();
return switch (id) {
case ClajNet.frameworkId -> readFramework(buffer);
case ClajNet.oldId -> throw new ArcNetException("Received a packet from the old CLaJ protocol");
case ClajNet.id -> readClaj(buffer);
default -> {
buffer.position(buffer.position() - 1);
throw new ArcNetException("Unknown protocol type: " + buffer.get());
}
default -> throw new ArcNetException("Unknown protocol type: " + id);
};
}

public Packet readClaj(ByteBuffer buffer) {
Packet packet = ClajNet.newPacket(buffer.get());

if (!packet.allow(false)) {
throw new ArcNetException("Invalid packet type for endpoint: " + packet.getClass());
}

Packet packet = ClajNet.newLocalPacket(buffer.get());
if (!packet.allow(false))
throw new ArcNetException("Invalid packet type for endpoint: " + packet.getClass().getName());
ByteBufferInput in = read.get();
in.buffer = buffer;

packet.read(in);
return packet;
}

@Override
public void write(ByteBuffer buffer, Object object) {

if (object instanceof ByteBuffer buf) {
buffer.put(buf);

} else if (object instanceof FrameworkMessage framework) {
writeFramework(buffer.put(ClajNet.frameworkId), framework);

} else if (object instanceof Packet packet) {
writeClaj(buffer, packet);

} else {
throw new ArcNetException("Unknown packet type: " + object.getClass());
switch (object) {
case ByteBuffer buf -> buffer.put(buf);
case FrameworkMessage framework -> writeFramework(buffer.put(ClajNet.frameworkId), framework);
case RawPacket raw -> raw.write(buffer);
case Packet packet -> writeClaj(buffer.put(ClajNet.id), packet);
default -> throw new ArcNetException("Unknown packet type: " + object.getClass().getName());
}
}

public void writeClaj(ByteBuffer buffer, Packet packet) {
if (!(packet instanceof RawPacket)) {
buffer.put(ClajNet.id).put(ClajNet.getId(packet));
}

buffer.put(ClajNet.getId(packet));
ByteBufferOutput out = write.get();
out.buffer = buffer;

packet.write(out);
}

/*
// Default methods sends a signed short instead of an unsigned one...
@Override
public void writeLength(ByteBuffer buffer, int length) {
buffer.putChar((char)length);
}

@Override
public int readLength(ByteBuffer buffer) {
return buffer.getChar();
}
*/
}
4 changes: 2 additions & 2 deletions src/java/api/src/com/xpdustry/claj/api/ClajLink.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public ClajLink(String host, int port, String roomId) {

try { uri = new URI(PROTOCOL, null, host, port, '/'+encodedRoomId, null, null); }
// This error can only happen when the host is invalid
catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid host"); }
catch (URISyntaxException _) { throw new IllegalArgumentException("Invalid host"); }
}

public ClajLink(String host, int port, long roomId) {
Expand All @@ -76,7 +76,7 @@ public ClajLink(String host, int port, long roomId) {

try { uri = new URI(PROTOCOL, null, host, port, '/'+encodedRoomId, null, null); }
// This error can only happen when the host is invalid
catch (URISyntaxException e) { throw new IllegalArgumentException("Invalid host"); }
catch (URISyntaxException _) { throw new IllegalArgumentException("Invalid host"); }
}

@Override
Expand Down
39 changes: 24 additions & 15 deletions src/java/api/src/com/xpdustry/claj/api/ClajPinger.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
import com.xpdustry.claj.common.ClajNet;
import com.xpdustry.claj.common.ClajPackets.Disconnect;
import com.xpdustry.claj.common.net.ClientReceiver;
import com.xpdustry.claj.common.net.NetListenerFilter;
import com.xpdustry.claj.common.packets.*;
import com.xpdustry.claj.common.status.*;


// FIXME: see ClajPingerManager comment
/**
* Note that {@link #pingHost}, {@link #requestRoomList} and {@link #joinRoom} are async operations.<br>
* If one of them are called while another is running, the last one is canceled.
* Note that {@link #pingHost}, {@link #requestRoomList} and {@link #joinRoom} are non-blocking operations. <br>
* But if one of them are called while another is running, the last one is canceled.
*/
public class ClajPinger extends Client {
public static final short NO_PASSWORD = -1;
Expand All @@ -58,6 +58,7 @@ public class ClajPinger extends Client {

protected final ClajProvider provider;
protected final ClientReceiver receiver;
protected final Selector selector;
protected String connectHost;
protected int connectPort;
protected volatile boolean shutdown = true, starting, connecting;
Expand Down Expand Up @@ -89,9 +90,10 @@ public ClajPinger(ClajProvider provider) {
super(8192, 8192, new Serializer());
((Serializer)getSerialization()).set(this);
this.provider = provider;
this.receiver = new ClientReceiver(this, null); // no need to delegate to the main thread
this.receiver = new ClientReceiver(this, NetListenerFilter.noIdleFilter);
this.selector = Reflect.get(Client.class, this, "selector");

receiver.handle(Disconnect.class, ignored -> {
receiver.handle(Disconnect.class, _ -> {
Throwable error = getLastProtocolError();
if (error != null) provider.handlePingerError(this, error);
failed(error);
Expand Down Expand Up @@ -127,8 +129,8 @@ public void update(int t) throws IOException {
public void run() {
shutdown = starting = false;
try { super.run(); }
catch (ClosedSelectorException e) {}
catch (ArcNetException e) {} // Already handled by disconnect event
catch (ClosedSelectorException _) {}
catch (ArcNetException _) {} // Already handled by disconnect event
catch (Exception e) {
provider.handlePingerError(this, e);
failed(e);
Expand All @@ -153,13 +155,12 @@ public void stop() {
shutdown = true;
}

@SuppressWarnings("resource")
@Override
public void close() {
if (canceling) {
close(DcReason.closed);
// Makes #close() doesn't wait for 'updateLock', which will makes #connect() cancelable
Reflect.<Selector>get(Client.class, this, "selector").wakeup();
selector.wakeup();
} else super.close();
}

Expand Down Expand Up @@ -374,7 +375,7 @@ public void pingHost(String host, int port, Cons<ServerState> success, Cons<Exce
return;
}
} else close();
//arc.util.Log.info("pinger: @, @, @", canceling, Thread.currentThread().getName(), System.currentTimeMillis());

resetPingState(success, failed);
setRequestTimeout(pingTimeout);
pinging = true;
Expand All @@ -391,6 +392,7 @@ public <T> void requestRoomList(String host, int port, Cons<Seq<ClajRoom<T>>> ro
return;
}
} else close();

resetListState(rooms, failed);
setRequestTimeout(listTimeout);
listing = true;
Expand Down Expand Up @@ -418,6 +420,7 @@ protected void joinRoom(String host, int port, long roomId, boolean withPassword
return;
}
} else close();

resetJoinState(success, reject, failed);
requestedRoom = roomId;
setRequestTimeout(joinTimeout);
Expand All @@ -436,6 +439,7 @@ public <T> void requestRoomInfo(String host, int port, long roomId, Cons<ClajRoo
return;
}
} else close();

resetInfoState(info, notFound, failed);
requestedRoom = roomId;
setRequestTimeout(infoTimeout);
Expand All @@ -448,20 +452,25 @@ protected void requestServerStatus() {
sendUDP(FrameworkMessage.discoverHost);
}

/** Packet ids for optimization */
private static final byte
rip = ClajNet.getId(RoomInfoRequestPacket.class), rlp = ClajNet.getId(RoomListRequestPacket.class),
rjp = ClajNet.getId(RoomJoinRequestPacket.class);

protected void requestRoomInfo(long roomId) {
RoomInfoRequestPacket p = new RoomInfoRequestPacket();
RoomInfoRequestPacket p = ClajNet.newLocalPacket(rip);
p.roomId = roomId;
sendTCP(p);
}

protected void requestRoomList() {
RoomListRequestPacket p = new RoomListRequestPacket();
RoomListRequestPacket p = ClajNet.newLocalPacket(rlp);
p.type = provider.getType();
sendTCP(p);
}

protected void requestRoomJoin(long roomId, boolean withPassword, short password) {
RoomJoinRequestPacket p = new RoomJoinRequestPacket();
RoomJoinRequestPacket p = ClajNet.newLocalPacket(rjp);
p.roomId = roomId;
p.withPassword = withPassword && password != NO_PASSWORD;
p.password = password;
Expand All @@ -473,7 +482,7 @@ protected void requestRoomJoin(long roomId, boolean withPassword, short password
protected ByteBuffer makeJoinPacket(RoomJoinRequestPacket request) {
if (request == null) return null;
ByteBuffer buff = ByteBuffer.allocate(RoomJoinRequestPacket.SIZE);
getSerialization().write(buff, request.toJoinPacket()); // not thread-safe // sure?
getSerialization().write(buff, request.toJoinPacket());
return (ByteBuffer)buff.flip();
}

Expand All @@ -496,4 +505,4 @@ public Object read(ByteBuffer buffer) {
return super.read(buffer);
}
}
}
}
5 changes: 2 additions & 3 deletions src/java/api/src/com/xpdustry/claj/api/ClajPingerManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,15 @@ public void dispose() {
if (pinger == null) continue;
pinger.stop();
try { pinger.dispose(); }
catch (Exception e) {}
catch (Exception _) {}
}
}

/** Stop all pingers and cancel the queue. */
public void stop() {
cancel();
for (ClajPinger pinger : pingers) {
if (pinger == null) continue;
pinger.stop();
if (pinger != null) pinger.stop();
}
}

Expand Down
Loading
Loading