-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
372 additions
and
2 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
app/src/main/java/net/imshit/aircraftwar/data/fighting/CommunicateInfo.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package net.imshit.aircraftwar.data.fighting | ||
|
||
data class CommunicateInfo( | ||
val userId: Int, | ||
val score: Int, | ||
val life: Int | ||
) |
64 changes: 64 additions & 0 deletions
64
app/src/main/java/net/imshit/aircraftwar/data/fighting/FightingClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
package net.imshit.aircraftwar.data.fighting | ||
|
||
import android.content.Context | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.launch | ||
import net.imshit.aircraftwar.data.account.LoginManager | ||
import okhttp3.OkHttpClient | ||
import okhttp3.Request | ||
import okhttp3.WebSocket | ||
import okhttp3.WebSocketListener | ||
import org.json.JSONObject | ||
import java.util.concurrent.TimeUnit | ||
|
||
class FightingClient( | ||
private val context: Context, | ||
private val roomId: Int, | ||
) : WebSocketListener() { | ||
|
||
companion object Const { | ||
const val SOCKET_URL = "wss://haxiaoshen.top/game/fighting" | ||
} | ||
|
||
private val httpClient = OkHttpClient.Builder().pingInterval(30, TimeUnit.SECONDS).build() | ||
|
||
private var webSocket: WebSocket? = null | ||
private val loginManager = LoginManager(context) | ||
|
||
fun run() { | ||
CoroutineScope(Dispatchers.Default).launch { | ||
if (loginManager.requireLogin()) { | ||
val request = | ||
Request.Builder().url("$SOCKET_URL/$roomId?token=${loginManager.token}") | ||
.build() | ||
webSocket = httpClient.newWebSocket(request, this@FightingClient) | ||
} | ||
} | ||
} | ||
|
||
var onData: ((CommunicateInfo) -> Unit)? = null | ||
var onQuit: (() -> Unit)? = null | ||
|
||
override fun onMessage(webSocket: WebSocket, text: String) { | ||
val jsonObject = JSONObject(text) | ||
val type = jsonObject.getString("type") | ||
if (type == "comm") { | ||
val jsonInfo = jsonObject.getJSONObject("msg") | ||
val userId = jsonInfo.getInt("user") | ||
val score = jsonInfo.getInt("score") | ||
val life = jsonInfo.getInt("life") | ||
onData?.invoke( | ||
CommunicateInfo( | ||
userId, score, life | ||
) | ||
) | ||
} else if (type == "quit") { | ||
onQuit?.invoke() | ||
} | ||
} | ||
|
||
fun send(info: CommunicateInfo) { | ||
webSocket?.send("""{"user":${info.userId}, "score":${info.score}, "life":${info.life}}""") | ||
} | ||
} |
69 changes: 69 additions & 0 deletions
69
app/src/main/java/net/imshit/aircraftwar/data/pairing/PairingClient.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package net.imshit.aircraftwar.data.pairing | ||
|
||
import android.content.Context | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.launch | ||
import net.imshit.aircraftwar.data.account.LoginManager | ||
import net.imshit.aircraftwar.logic.game.Difficulty | ||
import okhttp3.OkHttpClient | ||
import okhttp3.Request | ||
import okhttp3.WebSocket | ||
import okhttp3.WebSocketListener | ||
import org.json.JSONObject | ||
import java.util.concurrent.TimeUnit | ||
|
||
class PairingClient( | ||
private val context: Context, | ||
private val mode: Difficulty, | ||
) : WebSocketListener() { | ||
|
||
companion object Const { | ||
const val SOCKET_URL = "wss://haxiaoshen.top/game/pairing" | ||
} | ||
|
||
private val httpClient = OkHttpClient.Builder().pingInterval(30, TimeUnit.SECONDS).build() | ||
|
||
private var webSocket: WebSocket? = null | ||
private val loginManager = LoginManager(context) | ||
|
||
fun run() { | ||
CoroutineScope(Dispatchers.Default).launch { | ||
if (loginManager.requireLogin()) { | ||
val request = Request.Builder() | ||
.url("$SOCKET_URL?token=${loginManager.token}&mode=${mode.name.lowercase()}") | ||
.build() | ||
webSocket = httpClient.newWebSocket(request, this@PairingClient) | ||
} | ||
} | ||
} | ||
|
||
var onChange: ((List<PairingInfo>) -> Unit)? = null | ||
var onSucceed: ((Int) -> Unit)? = null | ||
|
||
override fun onMessage(webSocket: WebSocket, text: String) { | ||
val jsonObject = JSONObject(text) | ||
val type = jsonObject.getString("type") | ||
if (type == "player") { | ||
val jsonArray = jsonObject.getJSONArray("msg") | ||
val players = mutableListOf<PairingInfo>() | ||
for (i in 0 until jsonArray.length()) { | ||
val jsonPlayer = jsonArray.getJSONObject(i) | ||
players.add( | ||
PairingInfo( | ||
jsonPlayer.getInt("ID"), jsonPlayer.getString("name"), | ||
jsonPlayer.getBoolean("requesting") | ||
) | ||
) | ||
} | ||
onChange?.invoke(players) | ||
} else if (type == "room") { | ||
val room = jsonObject.getInt("msg") | ||
onSucceed?.invoke(room) | ||
} | ||
} | ||
|
||
fun select(userId: Int) { | ||
webSocket?.send("$userId") | ||
} | ||
} |
7 changes: 7 additions & 0 deletions
7
app/src/main/java/net/imshit/aircraftwar/data/scoreboard/SaveScoreDialog.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package net.imshit.aircraftwar.data.scoreboard | ||
|
||
import androidx.appcompat.app.AppCompatDialogFragment | ||
|
||
class SaveScoreDialog(onlineMode:Boolean):AppCompatDialogFragment() { | ||
|
||
} |
134 changes: 134 additions & 0 deletions
134
app/src/main/java/net/imshit/aircraftwar/gui/PairingActivity.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package net.imshit.aircraftwar.gui | ||
|
||
import android.content.Context | ||
import android.content.Intent | ||
import android.os.Bundle | ||
import android.view.LayoutInflater | ||
import android.view.View | ||
import android.view.ViewGroup | ||
import android.widget.ImageView | ||
import android.widget.TextView | ||
import androidx.appcompat.app.AppCompatActivity | ||
import androidx.recyclerview.widget.RecyclerView | ||
import com.google.android.material.button.MaterialButton | ||
import kotlinx.coroutines.CoroutineScope | ||
import kotlinx.coroutines.Dispatchers | ||
import kotlinx.coroutines.launch | ||
import net.imshit.aircraftwar.R | ||
import net.imshit.aircraftwar.data.account.LoginManager | ||
import net.imshit.aircraftwar.data.app.AppInfoDialog | ||
import net.imshit.aircraftwar.data.pairing.PairingClient | ||
import net.imshit.aircraftwar.data.pairing.PairingInfo | ||
import net.imshit.aircraftwar.databinding.ActivityPairingBinding | ||
import net.imshit.aircraftwar.logic.game.Difficulty | ||
|
||
class PairingActivity : AppCompatActivity() { | ||
companion object Api { | ||
fun actionStart(context: Context, gameMode: Difficulty, soundMode: Boolean) { | ||
CoroutineScope(Dispatchers.Default).launch { | ||
if (LoginManager(context).requireLogin()) { | ||
context.startActivity(Intent(context, PairingActivity::class.java).apply { | ||
putExtra("gameMode", gameMode) | ||
putExtra("soundMode", soundMode) | ||
}) | ||
} | ||
} | ||
} | ||
} | ||
|
||
class PairingInfoAdapter( | ||
private val activity: AppCompatActivity, | ||
private val client: PairingClient | ||
) : RecyclerView.Adapter<PairingInfoAdapter.PairingInfoViewHolder>() { | ||
class PairingInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { | ||
private val avatar: ImageView = itemView.findViewById(R.id.pvi_iv) | ||
private val accountView: TextView = itemView.findViewById(R.id.pvi_tv) | ||
private val button: MaterialButton = itemView.findViewById(R.id.pvi_btn) | ||
fun bind(pairingInfo: PairingInfo, context: Context, client: PairingClient) { | ||
this.accountView.text = pairingInfo.userAccount | ||
if (pairingInfo.isWilling) { | ||
this.avatar.setImageResource(R.drawable.avatar) | ||
} | ||
this.button.setOnClickListener { | ||
client.select(pairingInfo.userId) | ||
this.button.text = context.getString(R.string.button_pairing_sent) | ||
this.button.setIconResource(R.drawable.ic_check_24) | ||
} | ||
} | ||
} | ||
|
||
init { | ||
client.onChange = ::onDataChange | ||
} | ||
|
||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PairingInfoViewHolder { | ||
val view = LayoutInflater.from(parent.context) | ||
.inflate(R.layout.pairing_view_item, parent, false) | ||
return PairingInfoViewHolder(view) | ||
} | ||
|
||
private val buffer = mutableListOf<PairingInfo>() | ||
|
||
override fun getItemCount(): Int = buffer.size | ||
|
||
override fun onBindViewHolder(holder: PairingInfoViewHolder, position: Int) { | ||
holder.bind(buffer[position], activity, client) | ||
} | ||
|
||
private fun onDataChange(data: List<PairingInfo>) { | ||
// 清除已下线 | ||
buffer.removeIf { | ||
data.all { newItem -> newItem.userId != it.userId } | ||
} | ||
// 更新现有 | ||
buffer.forEach { oldItem -> | ||
val newItem = data.find { newItem -> newItem.userId == oldItem.userId } | ||
newItem?.let { | ||
oldItem.isWilling = it.isWilling | ||
} | ||
} | ||
// 新增新上线 | ||
buffer.addAll(data.filter { buffer.all { oldItem -> oldItem.userId != it.userId } }) | ||
activity.runOnUiThread { | ||
notifyDataSetChanged() | ||
} | ||
} | ||
} | ||
|
||
var gameMode: Difficulty = Difficulty.EASY | ||
var soundMode: Boolean = true | ||
|
||
override fun onCreate(savedInstanceState: Bundle?) { | ||
super.onCreate(savedInstanceState) | ||
// 获取配置 | ||
intent.apply { | ||
gameMode = getSerializableExtra("gameMode", Difficulty::class.java) ?: Difficulty.EASY | ||
soundMode = getBooleanExtra("soundMode", true) | ||
} | ||
with(ActivityPairingBinding.inflate(layoutInflater)) { | ||
setContentView(root) | ||
|
||
apTb.setNavigationOnClickListener { | ||
this@PairingActivity.finish() | ||
} | ||
|
||
apTb.setOnMenuItemClickListener { item -> | ||
when (item.itemId) { | ||
R.id.item_about -> AppInfoDialog().show(supportFragmentManager, "about") | ||
} | ||
return@setOnMenuItemClickListener true | ||
} | ||
|
||
val client = PairingClient(this@PairingActivity, gameMode) | ||
apRv.adapter = PairingInfoAdapter(this@PairingActivity, client) | ||
apRv.setHasFixedSize(true) | ||
client.onSucceed = ::onSucceed | ||
client.run() | ||
} | ||
} | ||
|
||
private fun onSucceed(room: Int) { | ||
GameActivity.actionStart(this, gameMode, soundMode, true, room) | ||
this.finish() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<vector android:height="24dp" android:tint="#000000" | ||
android:viewportHeight="24" android:viewportWidth="24" | ||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> | ||
<path android:fillColor="@android:color/white" android:pathData="M21,8L21,7l-3,2 -3,-2v1l3,2 3,-2zM22,3L2,3C0.9,3 0,3.9 0,5v14c0,1.1 0.9,2 2,2h20c1.1,0 1.99,-0.9 1.99,-2L24,5c0,-1.1 -0.9,-2 -2,-2zM8,6c1.66,0 3,1.34 3,3s-1.34,3 -3,3 -3,-1.34 -3,-3 1.34,-3 3,-3zM14,18L2,18v-1c0,-2 4,-3.1 6,-3.1s6,1.1 6,3.1v1zM22,12h-8L14,6h8v6z"/> | ||
</vector> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:app="http://schemas.android.com/apk/res-auto" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:fitsSystemWindows="true"> | ||
|
||
<com.google.android.material.appbar.AppBarLayout | ||
android:id="@+id/ap_abl" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:fitsSystemWindows="true"> | ||
|
||
<com.google.android.material.appbar.MaterialToolbar | ||
android:id="@+id/ap_tb" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:fitsSystemWindows="true" | ||
app:menu="@menu/main" | ||
app:navigationContentDescription="@string/navback" | ||
app:navigationIcon="@drawable/ic_arrow_back_24" | ||
app:title="@string/pairing_label" | ||
app:titleCentered="true" /> | ||
</com.google.android.material.appbar.AppBarLayout> | ||
|
||
<androidx.recyclerview.widget.RecyclerView | ||
android:id="@+id/ap_rv" | ||
android:layout_width="match_parent" | ||
android:layout_height="match_parent" | ||
android:orientation="vertical" | ||
app:layoutManager="androidx.recyclerview.widget.StaggeredGridLayoutManager" | ||
app:layout_behavior="@string/appbar_scrolling_view_behavior" | ||
app:spanCount="2" /> | ||
|
||
</androidx.coordinatorlayout.widget.CoordinatorLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android" | ||
xmlns:app="http://schemas.android.com/apk/res-auto" | ||
xmlns:tools="http://schemas.android.com/tools" | ||
android:id="@+id/pvi_card" | ||
style="?attr/materialCardViewOutlinedStyle" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:layout_marginHorizontal="16dp" | ||
android:layout_marginVertical="8dp" | ||
android:clickable="true" | ||
android:focusable="true"> | ||
|
||
<LinearLayout | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:orientation="vertical" | ||
android:padding="8dp"> | ||
|
||
<ImageView | ||
android:id="@+id/pvi_iv" | ||
android:layout_width="match_parent" | ||
android:layout_height="wrap_content" | ||
android:adjustViewBounds="true" | ||
android:contentDescription="@string/avatar" /> | ||
|
||
<TextView | ||
android:id="@+id/pvi_tv" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:layout_margin="8dp" | ||
android:fontFamily="sans-serif" | ||
android:layout_gravity="left" | ||
android:textFontWeight="450" | ||
android:textSize="24sp" | ||
tools:text="哈小深" /> | ||
|
||
<Button | ||
android:id="@+id/pvi_btn" | ||
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal" | ||
android:layout_width="wrap_content" | ||
android:layout_height="wrap_content" | ||
android:layout_margin="8dp" | ||
android:text="@string/button_pairing" | ||
android:layout_gravity="end" | ||
app:icon="@drawable/ic_contact_mail_24" /> | ||
|
||
</LinearLayout> | ||
|
||
</com.google.android.material.card.MaterialCardView> |