diff --git a/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt b/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt index 0155341cf..ff466ff32 100644 --- a/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt +++ b/app/src/main/java/com/chwl/app/ui/utils/ImageLoad.kt @@ -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 } diff --git a/app/src/module_game/java/com/chwl/app/game/core/BaseGameActivity.kt b/app/src/module_game/java/com/chwl/app/game/core/BaseGameActivity.kt index 1c85e5993..e2df49e6c 100644 --- a/app/src/module_game/java/com/chwl/app/game/core/BaseGameActivity.kt +++ b/app/src/module_game/java/com/chwl/app/game/core/BaseGameActivity.kt @@ -17,8 +17,11 @@ import com.netease.nim.uikit.StatusBarUtil abstract class BaseGameActivity : BaseViewBindingActivity(), RoomView { protected val viewModel: GameViewModel by viewModels() - protected val gameViewModel: GameEngineViewModel by viewModels() + protected val gameEngineViewModel: GameEngineViewModel by viewModels() protected var widgets: HashMap = HashMap() + protected val gameContext get() = viewModel.gameContextLiveData.value + + protected val stateAbility get() = gameContext?.findAbility(GameStateAbility::class.java.simpleName) override fun init() { initView() diff --git a/app/src/module_game/java/com/chwl/app/game/core/GameContext.kt b/app/src/module_game/java/com/chwl/app/game/core/GameContext.kt index 01127a632..db5b678eb 100644 --- a/app/src/module_game/java/com/chwl/app/game/core/GameContext.kt +++ b/app/src/module_game/java/com/chwl/app/game/core/GameContext.kt @@ -7,8 +7,13 @@ class GameContext(roomId: Long) : RoomContext(roomId) { override fun loadAbility(list: MutableMap) { 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() + } } \ No newline at end of file diff --git a/app/src/module_game/java/com/chwl/app/game/core/GameIMEngineAbility.kt b/app/src/module_game/java/com/chwl/app/game/core/GameIMEngineAbility.kt index e9e887ed8..b95d48bc7 100644 --- a/app/src/module_game/java/com/chwl/app/game/core/GameIMEngineAbility.kt +++ b/app/src/module_game/java/com/chwl/app/game/core/GameIMEngineAbility.kt @@ -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 = SafeListenerOwner()) : RoomAbility(), ListenerStore by listenerOwner { - private var chatRoomClient: ChatRoomClient? = null - val stateFlow = MutableStateFlow(StatusCode.INVALID) - fun enterRoom(sessionId: String) { + private var chatRoomClient: ChatRoomClient? = null + + private val stateAbility: GameStateAbility? + get() = roomContext?.findAbility( + 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 = MutableStateFlow(0) + /** + * 游戏状态: 本地定义状态+匹配状态 + * 本地定义状态:(NULL:不合法状态) + * 匹配状态(服务端定义):(0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败) + */ + val gameStateFlow: MutableStateFlow = MutableStateFlow(0) - fun requestRoomInfo() { + val gameIconFlow = MutableStateFlow(null) + + val gameIdFlow = MutableStateFlow(null) + + val roomIdFlow = MutableStateFlow(null) + + val imIdFlow = MutableStateFlow(null) + + val scoresFlow = MutableStateFlow?>(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 + } } \ No newline at end of file diff --git a/app/src/module_game/java/com/chwl/app/game/data/GameModel2.kt b/app/src/module_game/java/com/chwl/app/game/data/GameModel2.kt index d3cbd474a..b6ad064a1 100644 --- a/app/src/module_game/java/com/chwl/app/game/data/GameModel2.kt +++ b/app/src/module_game/java/com/chwl/app/game/data/GameModel2.kt @@ -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 + @GET("chatRoom/get") + suspend fun getChatRoomInfo(@Query("roomType") roomType: Int): ServiceResult /** * 首页游戏配置 @@ -54,7 +54,7 @@ object GameModel2 : BaseModel() { suspend fun startGame( @Field("mgId") mgId: String, @Field("gameMode") gameMode: Int - ): ServiceResult + ): ServiceResult } } \ No newline at end of file diff --git a/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomData.kt b/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomData.kt new file mode 100644 index 000000000..ea34e81ab --- /dev/null +++ b/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomData.kt @@ -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? = null + + // 匹配状态(0:匹配中、1:匹配成功、2:游戏结束、3:匹配失败) + val matchStatus: Int? = null + + // 轮次状态(0:进行中、1:结束) + val roundStatus: Int? = null +} \ No newline at end of file diff --git a/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomInfo.kt b/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomInfo.kt index cddd555b8..098fca780 100644 --- a/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomInfo.kt +++ b/app/src/module_game/java/com/chwl/app/game/data/bean/GameRoomInfo.kt @@ -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() { } \ No newline at end of file diff --git a/app/src/module_game/java/com/chwl/app/game/ui/buy/GameBuyDialog.kt b/app/src/module_game/java/com/chwl/app/game/ui/buy/GameBuyDialog.kt index 8577bf6d0..1e24268ac 100644 --- a/app/src/module_game/java/com/chwl/app/game/ui/buy/GameBuyDialog.kt +++ b/app/src/module_game/java/com/chwl/app/game/ui/buy/GameBuyDialog.kt @@ -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) { diff --git a/app/src/module_game/java/com/chwl/app/game/ui/game/GameActivity.kt b/app/src/module_game/java/com/chwl/app/game/ui/game/GameActivity.kt index 63b345926..0a72f556b 100644 --- a/app/src/module_game/java/com/chwl/app/game/ui/game/GameActivity.kt +++ b/app/src/module_game/java/com/chwl/app/game/ui/game/GameActivity.kt @@ -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(), RoomView, ILog { @@ -32,12 +41,12 @@ class GameActivity : BaseGameActivity(), 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(), 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(), RoomView, ILog { override fun initObserver() { super.initObserver() + viewModel.gameContextLiveData.observe(this) { + updateGameContext(it) + } + } + + private fun updateGameContext(gameContext: GameContext) { + val stateAbility = + gameContext.findAbility(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() { diff --git a/app/src/module_game/java/com/chwl/app/game/ui/game/GameViewModel.kt b/app/src/module_game/java/com/chwl/app/game/ui/game/GameViewModel.kt index 4b8bcc692..4568e32e5 100644 --- a/app/src/module_game/java/com/chwl/app/game/ui/game/GameViewModel.kt +++ b/app/src/module_game/java/com/chwl/app/game/ui/game/GameViewModel.kt @@ -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::class.java.simpleName)?.enterRoom( - InitialModel.get().publicChatSessionId) } override fun onCleared() { diff --git a/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeFragment.kt b/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeFragment.kt index dbca790cd..2873c3cbe 100644 --- a/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeFragment.kt +++ b/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeFragment.kt @@ -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(), Mai ChargeActivity.start(context) } binding.ivRank.singleClick { - toast("RANK") + CommonWebViewActivity.start(requireContext(), UriProvider.getGameRank()) } adapter.setOnItemClickListener { _, view, position -> val config = viewModel.gameConfigLiveData.value?.data diff --git a/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeViewModel.kt b/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeViewModel.kt index 9cd3420f4..f67be5f61 100644 --- a/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeViewModel.kt +++ b/app/src/module_game/java/com/chwl/app/game/ui/home/GameHomeViewModel.kt @@ -11,7 +11,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow class GameHomeViewModel : BaseViewModel() { val gameConfigLiveData = MutableLiveData?>() - val startGameFlow = MutableSharedFlow>() + val startGameFlow = MutableSharedFlow>() fun getGameList() { safeLaunch(onError = { diff --git a/app/src/module_game/res/layout/game_activity.xml b/app/src/module_game/res/layout/game_activity.xml index e8af7d803..d52e2412b 100644 --- a/app/src/module_game/res/layout/game_activity.xml +++ b/app/src/module_game/res/layout/game_activity.xml @@ -25,6 +25,7 @@ app:layout_constraintTop_toTopOf="parent" /> : Serializable { + companion object { + const val ROOM_TYPE_GAME = 0 + } + + val chatRoomId: Long? = null + + // 云信ID + val roomId: Long? = null + + val roomMics: MutableList? = null + + val data: T? = null + + // 房间类型(0:小游戏) + val roomType: Int? = null +} \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/bean/room/RoomMicBean.kt b/core/src/main/java/com/chwl/core/bean/room/RoomMicBean.kt new file mode 100644 index 000000000..63c3c894b --- /dev/null +++ b/core/src/main/java/com/chwl/core/bean/room/RoomMicBean.kt @@ -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 +} \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/bean/room/RoomMicUserInfo.kt b/core/src/main/java/com/chwl/core/bean/room/RoomMicUserInfo.kt new file mode 100644 index 000000000..801f116ab --- /dev/null +++ b/core/src/main/java/com/chwl/core/bean/room/RoomMicUserInfo.kt @@ -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 +} \ No newline at end of file diff --git a/core/src/main/java/com/chwl/core/support/room/RoomContext.kt b/core/src/main/java/com/chwl/core/support/room/RoomContext.kt index 7cb051fb4..8fc361463 100644 --- a/core/src/main/java/com/chwl/core/support/room/RoomContext.kt +++ b/core/src/main/java/com/chwl/core/support/room/RoomContext.kt @@ -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()