feat:完成部分房间信息获取逻辑对接

This commit is contained in:
max
2024-05-29 19:31:29 +08:00
parent 65ef4810e3
commit 2396eb9089
19 changed files with 234 additions and 33 deletions

View File

@@ -85,6 +85,14 @@ fun ImageView.loadAvatar(url: String?) {
.into(this)
}
fun ImageView.loadImage(url: String? = "") {
if (context.isDestroyed()) return
GlideApp.with(context).load(url)
.dontAnimate()
.into(this)
}
fun Context.isDestroyed(): Boolean {
return (getActivityContext(this) as? Activity)?.isDestroyed == true
}

View File

@@ -17,8 +17,11 @@ import com.netease.nim.uikit.StatusBarUtil
abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(), RoomView {
protected val viewModel: GameViewModel by viewModels()
protected val gameViewModel: GameEngineViewModel by viewModels()
protected val gameEngineViewModel: GameEngineViewModel by viewModels()
protected var widgets: HashMap<String, RoomWidget> = HashMap()
protected val gameContext get() = viewModel.gameContextLiveData.value
protected val stateAbility get() = gameContext?.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
override fun init() {
initView()

View File

@@ -7,8 +7,13 @@ class GameContext(roomId: Long) : RoomContext(roomId) {
override fun loadAbility(list: MutableMap<String, RoomAbility>) {
super.loadAbility(list)
list.put(GameStateAbility::class.java.simpleName, GameStateAbility())
list.put(GameIMEngineAbility::class.java.simpleName, GameIMEngineAbility())
list.put(GameQueueAbility::class.java.simpleName, GameQueueAbility())
list.put(GameMessageAbility::class.java.simpleName, GameMessageAbility())
}
override fun performStart() {
super.performStart()
}
}

View File

@@ -12,20 +12,38 @@ import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import io.reactivex.Single
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.collectLatest
import java.lang.IllegalStateException
class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineAbility.Listener> = SafeListenerOwner()) :
RoomAbility(), ListenerStore<GameIMEngineAbility.Listener> by listenerOwner {
private var chatRoomClient: ChatRoomClient? = null
val stateFlow = MutableStateFlow<StatusCode>(StatusCode.INVALID)
fun enterRoom(sessionId: String) {
private var chatRoomClient: ChatRoomClient? = null
private val stateAbility: GameStateAbility?
get() = roomContext?.findAbility<GameStateAbility>(
GameStateAbility::class.java.simpleName
)
override fun onStart(context: RoomContext) {
super.onStart(context)
safeLaunch {
stateAbility?.imIdFlow?.collectLatest {
loadIM(it?.toString())
}
}
}
private fun loadIM(sessionId: String?) {
if (chatRoomClient != null && chatRoomClient?.sessionId != sessionId) {
chatRoomClient?.onCleared()
chatRoomClient = null
}
if (sessionId != null) {
initClient(sessionId)
}
initClient(sessionId)
}
private fun initClient(sessionId: String) {
@@ -69,6 +87,7 @@ class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineA
super.onStop(context)
listenerOwner.removeAllListener()
chatRoomClient?.onCleared()
chatRoomClient = null
}
interface Listener {

View File

@@ -1,16 +1,56 @@
package com.chwl.app.game.core
import com.chwl.app.game.data.GameModel2
import com.chwl.app.game.data.bean.GameRoomInfo
import com.chwl.core.support.room.RoomAbility
import com.chwl.core.support.room.RoomContext
import kotlinx.coroutines.flow.MutableStateFlow
class GameStateAbility : RoomAbility() {
val gameState: MutableStateFlow<Int> = MutableStateFlow(0)
/**
* 游戏状态: 本地定义状态+匹配状态
* 本地定义状态NULL:不合法状态)
* 匹配状态(服务端定义)0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败)
*/
val gameStateFlow: MutableStateFlow<Int?> = MutableStateFlow(0)
fun requestRoomInfo() {
val gameIconFlow = MutableStateFlow<String?>(null)
val gameIdFlow = MutableStateFlow<String?>(null)
val roomIdFlow = MutableStateFlow<Long?>(null)
val imIdFlow = MutableStateFlow<Long?>(null)
val scoresFlow = MutableStateFlow<List<Double>?>(null)
override fun onStart(context: RoomContext) {
super.onStart(context)
requestRoomInfo()
}
private fun requestRoomInfo() {
safeLaunch {
val info = GameModel2.getGameRoomInfo()
if (info != null) {
syncRoomInfo(info)
} else {
syncGameState(null)
}
}
}
private fun syncRoomInfo(info: GameRoomInfo) {
roomIdFlow.value = info.chatRoomId
imIdFlow.value = info.roomId
gameIdFlow.value = info.data?.mgId
gameIconFlow.value = info.data?.gameRoomIcon
scoresFlow.value = info.data?.scores
syncGameState(info.data?.matchStatus)
}
private fun syncGameState(matchStatus: Int?) {
gameStateFlow.value = matchStatus
}
}

View File

@@ -4,6 +4,7 @@ import com.chwl.app.game.data.bean.GameConfigBean
import com.chwl.app.game.data.bean.GameRoomInfo
import com.chwl.core.base.BaseModel
import com.chwl.core.bean.response.ServiceResult
import com.chwl.core.bean.room.BaseRoomInfo
import com.chwl.core.home.bean.*
import com.chwl.core.utils.net.launchRequest
import com.chwl.library.net.rxnet.RxNet
@@ -11,6 +12,7 @@ import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
object GameModel2 : BaseModel() {
@@ -23,22 +25,20 @@ object GameModel2 : BaseModel() {
suspend fun getGameRoomInfo(): GameRoomInfo? =
launchRequest {
api.getGameRoomInfo()
api.getChatRoomInfo(BaseRoomInfo.ROOM_TYPE_GAME)
}
suspend fun startGame(gameId: String, gameMode: Int): String? =
suspend fun startGame(gameId: String, gameMode: Int): Long? =
launchRequest {
api.startGame(gameId, gameMode)
}
private interface Api {
/**
* 游戏房信息
*
* @return -
* 房信息
*/
@GET("resource/")
suspend fun getGameRoomInfo(): ServiceResult<GameRoomInfo>
@GET("chatRoom/get")
suspend fun getChatRoomInfo(@Query("roomType") roomType: Int): ServiceResult<GameRoomInfo>
/**
* 首页游戏配置
@@ -54,7 +54,7 @@ object GameModel2 : BaseModel() {
suspend fun startGame(
@Field("mgId") mgId: String,
@Field("gameMode") gameMode: Int
): ServiceResult<String>
): ServiceResult<Long>
}
}

View File

@@ -0,0 +1,18 @@
package com.chwl.app.game.data.bean
import androidx.annotation.Keep
import java.io.Serializable
@Keep
class GameRoomData : Serializable {
val mgId: String? = null
val gameRoomIcon: String? = null
val configJson: String? = null
val scores: MutableList<Double>? = null
// 匹配状态0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败)
val matchStatus: Int? = null
// 轮次状态0:进行中、1:结束)
val roundStatus: Int? = null
}

View File

@@ -1,8 +1,8 @@
package com.chwl.app.game.data.bean
import androidx.annotation.Keep
import java.io.Serializable
import com.chwl.core.bean.room.BaseRoomInfo
@Keep
class GameRoomInfo : Serializable {
class GameRoomInfo : BaseRoomInfo<GameRoomData>() {
}

View File

@@ -63,7 +63,7 @@ class GameBuyDialog(private val gameConfig: GameConfigBean, private val gameMode
if (it.isSuccess) {
dismissAllowingStateLoss()
val intent =
GameIntent(1, gameConfig.mgId ?: 0L, gameMode.gameMode ?: -1)
GameIntent(it.data ?: 0, gameConfig.mgId ?: 0L, gameMode.gameMode ?: -1)
GameActivity.start(requireContext(), intent)
} else {
if (it.code == BalanceNotEnoughExeption.code) {

View File

@@ -2,17 +2,26 @@ package com.chwl.app.game.ui.game
import android.content.Context
import android.content.Intent
import androidx.lifecycle.lifecycleScope
import com.chwl.app.R
import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener
import com.chwl.app.databinding.GameActivityBinding
import com.chwl.app.game.core.BaseGameActivity
import com.chwl.app.game.core.GameContext
import com.chwl.app.game.core.GameStateAbility
import com.chwl.app.game.core.engine.model.GameViewInfoModel.GameViewRectModel
import com.chwl.app.game.ui.game.widgets.bottom.GameBottomWidget
import com.chwl.app.game.ui.game.widgets.message.GameMessageWidget
import com.chwl.app.game.ui.game.widgets.queue.GameQueueWidget
import com.chwl.app.ui.utils.ImageLoadUtilsV2
import com.chwl.app.ui.utils.load
import com.chwl.app.ui.utils.loadImage
import com.chwl.core.support.room.RoomView
import com.example.lib_utils.ktx.singleClick
import com.example.lib_utils.log.ILog
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.launch
class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
@@ -32,12 +41,12 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
return
}
super.init()
initGameEngine()
viewModel.init(intentData)
initGameEngine(intentData)
}
private fun initGameEngine(intentData: GameIntent) {
gameViewModel.init(lifecycle, binding.layoutGame)
private fun initGameEngine() {
gameEngineViewModel.init(lifecycle, binding.layoutGame)
binding.spaceGameRect.post {
val rect = GameViewRectModel().apply {
top = binding.spaceGameRect.top
@@ -45,8 +54,7 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
}
logD("initGameEngine() height:${binding.root.height}")
logD("initGameEngine() top:${rect.top} bottom:${rect.bottom}")
gameViewModel.setGameViewRect(rect)
gameViewModel.loadGame(this, intentData.roomId.toString(), intentData.gameId)
gameEngineViewModel.setGameViewRect(rect)
}
}
@@ -59,6 +67,45 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
override fun initObserver() {
super.initObserver()
viewModel.gameContextLiveData.observe(this) {
updateGameContext(it)
}
}
private fun updateGameContext(gameContext: GameContext) {
val stateAbility =
gameContext.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
?: return
lifecycleScope.launch {
stateAbility.gameIconFlow.collectLatest {
binding.ivLogo.loadImage(it)
}
stateAbility.scoresFlow.collectLatest {
val number = it?.first()?.toString() ?: ""
binding.tvAwardValue.text = number
binding.tvAwardTips.text = getString(R.string.game_award_tips_format, number)
}
updateGameEngine(stateAbility)
}
}
private suspend fun updateGameEngine(stateAbility: GameStateAbility) {
stateAbility.imIdFlow.zip(stateAbility.roomIdFlow) { imId, roomId ->
if (imId != null && roomId != null) {
Pair(imId, roomId)
} else {
null
}
}.collectLatest {
if (it != null) {
gameEngineViewModel.loadGame(
this@GameActivity,
it.second.toString(),
it.first
)
}
}
}
override fun initWidgets() {

View File

@@ -3,9 +3,6 @@ package com.chwl.app.game.ui.game
import androidx.lifecycle.MutableLiveData
import com.chwl.app.base.BaseViewModel
import com.chwl.app.game.core.GameContext
import com.chwl.app.game.core.GameIMEngineAbility
import com.chwl.app.public_chat.core.ChatRoomClientManager
import com.chwl.core.initial.InitialModel
class GameViewModel : BaseViewModel() {
@@ -15,8 +12,6 @@ class GameViewModel : BaseViewModel() {
val gameContext = GameContext(intent.roomId)
gameContext.performStart()
gameContextLiveData.value = gameContext
gameContext.findAbility<GameIMEngineAbility>(GameIMEngineAbility::class.java.simpleName)?.enterRoom(
InitialModel.get().publicChatSessionId)
}
override fun onCleared() {

View File

@@ -10,7 +10,9 @@ import com.chwl.app.support.FragmentVisibleStateHelper
import com.chwl.app.ui.pay.ChargeActivity
import com.chwl.app.ui.utils.load
import com.chwl.app.ui.utils.loadAvatar
import com.chwl.app.ui.webview.CommonWebViewActivity
import com.chwl.app.ui.widget.recyclerview.decoration.GridSpacingItemNewDecoration
import com.chwl.core.UriProvider
import com.chwl.core.pay.PayModel
import com.chwl.core.pay.event.GetWalletInfoEvent
import com.chwl.core.pay.event.UpdateWalletInfoEvent
@@ -55,7 +57,7 @@ class GameHomeFragment : BaseViewBindingFragment<GameHomeFragmentBinding>(), Mai
ChargeActivity.start(context)
}
binding.ivRank.singleClick {
toast("RANK")
CommonWebViewActivity.start(requireContext(), UriProvider.getGameRank())
}
adapter.setOnItemClickListener { _, view, position ->
val config = viewModel.gameConfigLiveData.value?.data

View File

@@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
class GameHomeViewModel : BaseViewModel() {
val gameConfigLiveData = MutableLiveData<BeanResult<GameConfigBean>?>()
val startGameFlow = MutableSharedFlow<BeanResult<String>>()
val startGameFlow = MutableSharedFlow<BeanResult<Long>>()
fun getGameList() {
safeLaunch(onError = {

View File

@@ -25,6 +25,7 @@
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/iv_logo"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="@dimen/dp_11"

View File

@@ -303,6 +303,15 @@ public class UriProvider {
return JAVA_WEB_URL.concat("/molistar/modules/rule/luckyGiftRule.html?giftID=" + giftID);
}
/**
* 游戏排行榜
*/
public static String getGameRank() {
return JAVA_WEB_URL.concat("/molistar/modules/gameRank/index.html");
}
public static String toFullUrl(String shortUrl) {
if (shortUrl == null) {
return null;

View File

@@ -0,0 +1,23 @@
package com.chwl.core.bean.room
import androidx.annotation.Keep
import java.io.Serializable
@Keep
abstract class BaseRoomInfo<T> : Serializable {
companion object {
const val ROOM_TYPE_GAME = 0
}
val chatRoomId: Long? = null
// 云信ID
val roomId: Long? = null
val roomMics: MutableList<RoomMicBean>? = null
val data: T? = null
// 房间类型0:小游戏)
val roomType: Int? = null
}

View File

@@ -0,0 +1,16 @@
package com.chwl.core.bean.room
import androidx.annotation.Keep
import java.io.Serializable
@Keep
class RoomMicBean : Serializable {
val position: Int? = null
val micUser: RoomMicUserInfo? = null
// 是否被锁
val micState: Int? = null
// 是否被禁
val posState: Int? = null
}

View File

@@ -0,0 +1,12 @@
package com.chwl.core.bean.room
import androidx.annotation.Keep
import java.io.Serializable
@Keep
class RoomMicUserInfo : Serializable {
val avatar: String? = null
val erbanNo: Long? = null
val nick: String? = null
val uid: String? = null
}

View File

@@ -1,5 +1,6 @@
package com.chwl.core.support.room
import androidx.annotation.CallSuper
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.chwl.core.room.core.RoomDataService
@@ -12,7 +13,7 @@ import com.chwl.core.support.room.lifecycle.RoomLifecycleRegistry
* Desc:一个房间
* @param roomId roomUid
**/
abstract class RoomContext(val roomId: Long) : ILog {
abstract class RoomContext(var roomId: Long) : ILog {
/**
* 生命周期处理
@@ -31,7 +32,8 @@ abstract class RoomContext(val roomId: Long) : ILog {
/**
* 启动(进入房间)
*/
fun performStart() {
@CallSuper
open fun performStart() {
logI("performStart()", filePrinter = true)
roomLifecycle.handleLifecycleEvent(this, RoomLifecycle.Event.START)
}
@@ -39,7 +41,8 @@ abstract class RoomContext(val roomId: Long) : ILog {
/**
* 停止(退出房间)
*/
fun performStop() {
@CallSuper
open fun performStop() {
logI("performStop()", filePrinter = true)
roomLifecycle.handleLifecycleEvent(this, RoomLifecycle.Event.STOP)
onCleared()