feat:完善游戏房状态维护
This commit is contained in:
@@ -274,8 +274,6 @@ dependencies {
|
||||
if (!isolationMode && file("../modules/module_google/build.gradle").exists()) {
|
||||
implementation project(':modules:module_google')
|
||||
}
|
||||
|
||||
implementation 'tech.sud.mgp:SudMGP-static:1.3.3.1158'
|
||||
}
|
||||
|
||||
channel {
|
||||
|
@@ -18,6 +18,8 @@ import com.chwl.core.room.game.bean.GameCfg
|
||||
import com.chwl.core.room.game.GameModel
|
||||
import com.chwl.core.room.game.GameStatus
|
||||
import com.chwl.core.room.model.HomePartyModel
|
||||
import com.chwl.core.sud.state.SudMGPAPPState
|
||||
import com.chwl.core.sud.state.SudMGPMGState
|
||||
import com.chwl.core.user.UserModel
|
||||
import com.chwl.core.utils.LogUtils
|
||||
import com.chwl.core.utils.net.RxHelper
|
||||
@@ -386,7 +388,7 @@ class GameDelegate(val activity: Activity, val container: FrameLayout, var mgId:
|
||||
}
|
||||
}
|
||||
}
|
||||
SudMGPMGState.APP_COMMON_SELF_CLICK_JOIN_BTN -> {
|
||||
SudMGPMGState.MG_COMMON_SELF_CLICK_JOIN_BTN -> {
|
||||
|
||||
try {
|
||||
val jsonObject = JSONObject(dataJson)
|
||||
@@ -397,7 +399,7 @@ class GameDelegate(val activity: Activity, val container: FrameLayout, var mgId:
|
||||
}
|
||||
|
||||
}
|
||||
SudMGPMGState.APP_COMMON_SELF_CLICK_START_BTN -> {
|
||||
SudMGPMGState.MG_COMMON_SELF_CLICK_START_BTN -> {
|
||||
notifySelfPlayingState(true)
|
||||
}
|
||||
SudMGPMGState.MG_COMMON_GAME_STATE -> handleGameState(dataJson)
|
||||
|
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright © Sud.Tech
|
||||
https://sud.tech
|
||||
*/
|
||||
package com.chwl.app.avroom.game;
|
||||
|
||||
/**
|
||||
* Time:2021/10/19
|
||||
* Description: APP to MG 的状态定义
|
||||
*/
|
||||
public class SudMGPAPPState {
|
||||
|
||||
// region 通用状态
|
||||
|
||||
/**
|
||||
* 加入状态
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_IN = "app_common_self_in";
|
||||
|
||||
/**
|
||||
* 准备状态
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_READY = "app_common_self_ready";
|
||||
|
||||
/**
|
||||
* 游戏状态
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_PLAYING = "app_common_self_playing";
|
||||
|
||||
/**
|
||||
* 队长状态
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CAPTAIN = "app_common_self_captain";
|
||||
|
||||
/**
|
||||
* 踢人
|
||||
* v1.1.30.xx
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_KICK = "app_common_self_kick";
|
||||
|
||||
/**
|
||||
* 结束游戏
|
||||
* v1.1.30.xx
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_END = "app_common_self_end";
|
||||
|
||||
/**
|
||||
* 麦克风状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_MICROPHONE = "app_common_self_microphone";
|
||||
|
||||
/**
|
||||
* 文字命中状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_TEXT_HIT = "app_common_self_text_hit";
|
||||
|
||||
}
|
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
Copyright © Sud.Tech
|
||||
https://sud.tech
|
||||
*/
|
||||
package com.chwl.app.avroom.game;
|
||||
|
||||
/**
|
||||
* Time:2021/10/19
|
||||
* Description: MG to APP 的状态定义
|
||||
*/
|
||||
public class SudMGPMGState {
|
||||
|
||||
// region 通用状态-游戏
|
||||
|
||||
/**
|
||||
* 公屏消息 (已修改)
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String MG_COMMON_PUBLIC_MESSAGE = "mg_common_public_message";
|
||||
|
||||
/**
|
||||
* 关键词状态
|
||||
*/
|
||||
public static final String MG_COMMON_KEY_WORD_TO_HIT = "mg_common_key_word_to_hit";
|
||||
|
||||
// endregion 通用状态-游戏
|
||||
|
||||
|
||||
// region 通用状态-玩家
|
||||
|
||||
/**
|
||||
* 加入状态 (已修改)
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String MG_COMMON_PLAYER_IN = "mg_common_player_in";
|
||||
|
||||
/**
|
||||
* 准备状态 (已修改)
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String MG_COMMON_PLAYER_READY = "mg_common_player_ready";
|
||||
|
||||
/**
|
||||
* 队长状态 (已修改)
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String MG_COMMON_PLAYER_CAPTAIN = "mg_common_player_captain";
|
||||
|
||||
/**
|
||||
* 游戏状态 (已修改)
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String MG_COMMON_PLAYER_PLAYING = "mg_common_player_playing";
|
||||
|
||||
/**
|
||||
* 游戏状态(已修改)
|
||||
* 最低版本: v1.1.30.xx
|
||||
*/
|
||||
public static final String MG_COMMON_GAME_STATE = "mg_common_game_state";
|
||||
|
||||
// endregion 通用状态-玩家
|
||||
|
||||
|
||||
// region 碰碰我最强
|
||||
// endregion 碰碰我最强
|
||||
|
||||
// region 飞刀达人
|
||||
// endregion 飞刀达人
|
||||
|
||||
// region 你画我猜
|
||||
|
||||
/**
|
||||
* 选词中
|
||||
*/
|
||||
public static final String MG_DG_SELECTING = "mg_dg_selecting";
|
||||
|
||||
/**
|
||||
* 作画中
|
||||
*/
|
||||
public static final String MG_DG_PAINTING = "mg_dg_painting";
|
||||
|
||||
/**
|
||||
* 错误答案
|
||||
*/
|
||||
public static final String MG_DG_ERRORANSWER = "mg_dg_erroranswer";
|
||||
|
||||
/**
|
||||
* 总积分
|
||||
*/
|
||||
public static final String MG_DG_TOTALSCORE = "mg_dg_totalscore";
|
||||
|
||||
/**
|
||||
* 本次积分
|
||||
*/
|
||||
public static final String MG_DG_SCORE = "mg_dg_score";
|
||||
|
||||
// endregion 你画我猜
|
||||
|
||||
|
||||
/**
|
||||
* 加入游戏按钮点击状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CLICK_JOIN_BTN = "mg_common_self_click_join_btn";
|
||||
/**
|
||||
* 取消加入游戏按钮点击状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CLICK_CANCEL_JOIN_BTN = "mg_common_self_click_cancel_join_btn";
|
||||
/**
|
||||
* 准备按钮点击状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CLICK_READY_BTN = "mg_common_self_click_ready_btn";
|
||||
/**
|
||||
* 取消准备按钮点击状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CLICK_CANCEL_READY_BTN = "mg_common_self_click_cancel_ready_btn";
|
||||
/**
|
||||
* 开始游戏按钮点击状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CLICK_START_BTN = "mg_common_self_click_start_btn";
|
||||
/**
|
||||
* 分享按钮点击状态
|
||||
*/
|
||||
public static final String APP_COMMON_SELF_CLICK_SHARE_BTN = "mg_common_self_click_share_btn";
|
||||
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package com.chwl.app.support
|
||||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.chwl.app.BuildConfig
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.core.helper.PathHelper
|
||||
import com.chwl.core.home.model.HomeModel
|
||||
@@ -27,6 +28,10 @@ class PreloadResourceViewModel : BaseViewModel(), DownloadListener, ILog {
|
||||
private var isStarted = false
|
||||
|
||||
fun start() {
|
||||
if (BuildConfig.DEBUG) {
|
||||
// 太多请求了,影响查看控制台日志
|
||||
return
|
||||
}
|
||||
if (isStarted) {
|
||||
return
|
||||
}
|
||||
|
@@ -728,4 +728,5 @@
|
||||
<color name="color_10ECD6">#10ECD6</color>
|
||||
<color name="color_4D415E">#4D415E</color>
|
||||
<color name="color_DE3446">#DE3446</color>
|
||||
<color name="color_FF6629">#FF6629</color>
|
||||
</resources>
|
||||
|
@@ -1,18 +1,27 @@
|
||||
package com.chwl.app.game.core
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.View
|
||||
import android.widget.FrameLayout
|
||||
import androidx.activity.viewModels
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.base.BaseViewBindingActivity
|
||||
import com.chwl.app.common.widget.dialog.DialogManager
|
||||
import com.chwl.app.game.core.engine.GameEngineViewModel
|
||||
import com.chwl.app.game.data.bean.GameInfoUiState
|
||||
import com.chwl.app.game.ui.game.GameViewModel
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import com.chwl.core.support.room.RoomView
|
||||
import com.chwl.core.support.room.RoomWidget
|
||||
import com.netease.nim.uikit.StatusBarUtil
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.zip
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(), RoomView {
|
||||
|
||||
@@ -23,25 +32,110 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
|
||||
protected val stateAbility get() = gameContext?.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
|
||||
|
||||
private var gameInfoDialogManager: DialogManager? = null
|
||||
protected var loadingDialogManager: DialogManager? = null
|
||||
|
||||
override fun init() {
|
||||
initView()
|
||||
initEvent()
|
||||
initObserver()
|
||||
initWidgets()
|
||||
gameEngineViewModel.init(lifecycle)
|
||||
}
|
||||
|
||||
protected open fun initView() {
|
||||
gameInfoDialogManager = DialogManager(this)
|
||||
loadingDialogManager = DialogManager(this)
|
||||
}
|
||||
|
||||
protected open fun initEvent() {
|
||||
}
|
||||
|
||||
protected open fun initObserver() {
|
||||
viewModel.gameContextLiveData.observe(this) {
|
||||
onGameContext(it)
|
||||
}
|
||||
gameEngineViewModel.gameViewLiveData.observe(this) {
|
||||
onGameViewChanged(it)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun initWidgets() {
|
||||
}
|
||||
|
||||
protected open fun onGameContext(gameContext: GameContext) {
|
||||
gameEngineViewModel.setGameContext(gameContext)
|
||||
stateAbility?.let {
|
||||
observeGameInfoUiState(it)
|
||||
updateGameEngine(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun observeGameInfoUiState(stateAbility: GameStateAbility) {
|
||||
lifecycleScope.launch {
|
||||
stateAbility.gameInfoUiStateFlow.collectLatest {
|
||||
when (it) {
|
||||
is GameInfoUiState.Loading -> {
|
||||
gameInfoDialogManager?.showProgressDialog(context)
|
||||
}
|
||||
|
||||
is GameInfoUiState.Success -> {
|
||||
gameInfoDialogManager?.dismissDialog()
|
||||
}
|
||||
|
||||
is GameInfoUiState.Failed -> {
|
||||
gameInfoDialogManager?.dismissDialog()
|
||||
it.throwable.message?.let { msg ->
|
||||
toast(msg)
|
||||
}
|
||||
}
|
||||
|
||||
is GameInfoUiState.Empty -> {
|
||||
gameInfoDialogManager?.dismissDialog()
|
||||
toast(R.string.empty_data)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGameEngine(stateAbility: GameStateAbility) {
|
||||
lifecycleScope.launch {
|
||||
stateAbility.gameIdFlow.zip(stateAbility.roomIdFlow) { gameId, roomId ->
|
||||
if (gameId?.toLongOrNull() != null && roomId != null) {
|
||||
Pair(gameId.toLong(), roomId)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}.collectLatest {
|
||||
if (it != null) {
|
||||
gameEngineViewModel.loadGame(
|
||||
this@BaseGameActivity,
|
||||
it.second.toString(),
|
||||
it.first
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun onGameViewChanged(view: View?) {
|
||||
if (view == null) {
|
||||
getGameViewGroup().removeAllViews()
|
||||
} else {
|
||||
getGameViewGroup().addView(
|
||||
view,
|
||||
FrameLayout.LayoutParams(
|
||||
FrameLayout.LayoutParams.MATCH_PARENT,
|
||||
FrameLayout.LayoutParams.MATCH_PARENT
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun getGameViewGroup(): FrameLayout
|
||||
|
||||
/**
|
||||
* 注册组件
|
||||
*/
|
||||
@@ -93,4 +187,11 @@ abstract class BaseGameActivity<T : ViewBinding> : BaseViewBindingActivity<T>(),
|
||||
return widgets[name]
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
gameInfoDialogManager?.dismissDialog()
|
||||
gameInfoDialogManager = null
|
||||
loadingDialogManager?.dismissDialog()
|
||||
loadingDialogManager = null
|
||||
}
|
||||
}
|
@@ -11,6 +11,7 @@ import com.netease.nimlib.sdk.StatusCode
|
||||
import com.netease.nimlib.sdk.chatroom.ChatRoomMessageBuilder
|
||||
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
|
||||
import io.reactivex.Single
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import java.lang.IllegalStateException
|
||||
@@ -22,6 +23,8 @@ class GameIMEngineAbility(private val listenerOwner: ListenerOwner<GameIMEngineA
|
||||
|
||||
private var chatRoomClient: ChatRoomClient? = null
|
||||
|
||||
val receiveMessageFlow = MutableSharedFlow<List<ChatRoomMessage>>()
|
||||
|
||||
private val stateAbility: GameStateAbility?
|
||||
get() = roomContext?.findAbility<GameStateAbility>(
|
||||
GameStateAbility::class.java.simpleName
|
||||
|
@@ -1,7 +1,19 @@
|
||||
package com.chwl.app.game.core
|
||||
|
||||
import com.chwl.core.bean.room.RoomMicBean
|
||||
import com.chwl.core.support.room.RoomAbility
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class GameQueueAbility : RoomAbility() {
|
||||
|
||||
val queueFlow = MutableStateFlow<List<RoomMicBean>?>(null)
|
||||
|
||||
override fun onStart(context: RoomContext) {
|
||||
super.onStart(context)
|
||||
}
|
||||
|
||||
suspend fun updateQueue(data: List<RoomMicBean>?) {
|
||||
queueFlow.value = data
|
||||
}
|
||||
}
|
@@ -1,12 +1,18 @@
|
||||
package com.chwl.app.game.core
|
||||
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.app.game.data.bean.GameRoomInfo
|
||||
import com.chwl.app.game.data.bean.GameInfoUiState
|
||||
import com.chwl.core.bean.game.GameRoomInfo
|
||||
import com.chwl.core.im.custom.bean.CustomAttachment
|
||||
import com.chwl.core.im.custom.bean.GameQueueChangedAttachment
|
||||
import com.chwl.core.support.room.RoomAbility
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
|
||||
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class GameStateAbility : RoomAbility() {
|
||||
class GameStateAbility : RoomAbility(), GameIMEngineAbility.Listener {
|
||||
|
||||
/**
|
||||
* 游戏状态: 本地定义状态+匹配状态
|
||||
@@ -25,32 +31,98 @@ class GameStateAbility : RoomAbility() {
|
||||
|
||||
val scoresFlow = MutableStateFlow<List<Double>?>(null)
|
||||
|
||||
@Deprecated("里面的属性有可能不是最新的,建议通过具体属性flow获取数据")
|
||||
val gameInfoFlow = MutableStateFlow<GameRoomInfo?>(null)
|
||||
|
||||
val gameInfoUiStateFlow = MutableStateFlow<GameInfoUiState>(GameInfoUiState.Loading)
|
||||
|
||||
val matchFailedFlow = MutableSharedFlow<Boolean>()
|
||||
|
||||
private val queueAbility get() = roomContext?.findAbility<GameQueueAbility>(GameQueueAbility::class.java.simpleName)
|
||||
|
||||
override fun onStart(context: RoomContext) {
|
||||
super.onStart(context)
|
||||
requestRoomInfo()
|
||||
val imEngineAbility =
|
||||
context.findAbility<GameIMEngineAbility>(GameIMEngineAbility::class.java.simpleName)
|
||||
imEngineAbility?.addListener(this)
|
||||
}
|
||||
|
||||
private fun requestRoomInfo() {
|
||||
safeLaunch {
|
||||
gameInfoUiStateFlow.value = GameInfoUiState.Loading
|
||||
safeLaunch(onError = {
|
||||
gameInfoUiStateFlow.value = GameInfoUiState.Failed(it, gameInfoFlow.value)
|
||||
}) {
|
||||
val info = GameModel2.getGameRoomInfo()
|
||||
if (info != null) {
|
||||
gameInfoUiStateFlow.value = GameInfoUiState.Success
|
||||
syncRoomInfo(info)
|
||||
} else {
|
||||
gameInfoUiStateFlow.value = GameInfoUiState.Empty(gameInfoFlow.value)
|
||||
syncGameState(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncRoomInfo(info: GameRoomInfo) {
|
||||
private suspend fun syncRoomInfo(info: GameRoomInfo) {
|
||||
roomContext?.roomId = info.chatRoomId ?: 0
|
||||
gameInfoFlow.value = info
|
||||
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)
|
||||
syncQueue(info)
|
||||
}
|
||||
|
||||
private fun syncGameState(matchStatus: Int?) {
|
||||
gameStateFlow.value = matchStatus
|
||||
}
|
||||
|
||||
private suspend fun syncQueue(info: GameRoomInfo) {
|
||||
queueAbility?.updateQueue(info.roomMics)
|
||||
syncGameState(info.data?.matchStatus)
|
||||
}
|
||||
|
||||
override fun onReceiveMessage(messages: List<ChatRoomMessage>) {
|
||||
messages.forEach {
|
||||
onReceiveMessage(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onReceiveMessage(message: ChatRoomMessage) {
|
||||
if (message.msgType == MsgTypeEnum.custom) {
|
||||
val attachment: CustomAttachment = (message.attachment as? CustomAttachment) ?: return
|
||||
when (attachment.first) {
|
||||
CustomAttachment.CUSTOM_MSG_MINI_GAME -> {
|
||||
when (attachment.second) {
|
||||
// 麦位变更
|
||||
CustomAttachment.CUSTOM_MSG_MINI_GAME_QUEUE_CHANGED -> {
|
||||
val gameInfo =
|
||||
(attachment as? GameQueueChangedAttachment)?.gameInfo ?: return
|
||||
safeLaunch {
|
||||
syncQueue(gameInfo)
|
||||
}
|
||||
}
|
||||
|
||||
// 匹配失败
|
||||
CustomAttachment.CUSTOM_MSG_MINI_GAME_MATCH_FAILED -> {
|
||||
safeLaunch {
|
||||
gameStateFlow.value = 3
|
||||
matchFailedFlow.emit(true)
|
||||
}
|
||||
}
|
||||
|
||||
// 提前结束
|
||||
CustomAttachment.CUSTOM_MSG_MINI_GAME_FORCED_END -> {
|
||||
safeLaunch {
|
||||
gameStateFlow.value = 2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -8,45 +8,60 @@ import android.widget.FrameLayout
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.avroom.game.AppConfig
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.core.engine.model.GameStateResponse
|
||||
import com.chwl.app.game.core.engine.model.GameViewInfoModel
|
||||
import com.chwl.app.game.core.engine.model.GameViewInfoModel.GameViewRectModel
|
||||
import com.chwl.app.game.core.GameContext
|
||||
import com.chwl.app.game.core.GameQueueAbility
|
||||
import com.chwl.app.game.core.GameStateAbility
|
||||
import com.chwl.core.auth.AuthModel
|
||||
import com.chwl.core.room.game.GameModel
|
||||
import com.chwl.core.room.game.bean.GameCfg
|
||||
import com.chwl.core.sud.decorator.SudFSMMGDecorator
|
||||
import com.chwl.core.sud.decorator.SudFSMMGListener
|
||||
import com.chwl.core.sud.decorator.SudFSTAPPDecorator
|
||||
import com.chwl.core.sud.model.GameViewInfoModel
|
||||
import com.chwl.core.sud.state.MGStateResponse
|
||||
import com.chwl.core.sud.state.SudMGPMGState
|
||||
import com.chwl.library.language.LanguageHelper
|
||||
import com.chwl.library.utils.SingleToastUtil
|
||||
import com.chwl.library.utils.json.JsonUtils
|
||||
import com.example.lib_utils.log.ILog
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import tech.sud.mgp.core.ISudFSMStateHandle
|
||||
import tech.sud.mgp.core.ISudListenerInitSDK
|
||||
import tech.sud.mgp.core.SudMGP
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
open class GameEngineViewModel : BaseViewModel(), ILog, LifecycleEventObserver {
|
||||
open class GameEngineViewModel : BaseViewModel(), SudFSMMGListener, ILog,
|
||||
LifecycleEventObserver {
|
||||
|
||||
val gameViewLiveData = MutableLiveData<View>(null)
|
||||
private var isRunning = true
|
||||
|
||||
private val gameFSMMG = GameSudFSMMG(this)
|
||||
|
||||
private val gameFSTAPP = GameSudFSTAPP(this)
|
||||
|
||||
private val sudFSMMG = SudFSMMGDecorator().apply {
|
||||
setSudFSMMGListener(this@GameEngineViewModel)
|
||||
}
|
||||
private val sudFSTAPP = SudFSTAPPDecorator()
|
||||
private var lifecycle: Lifecycle? = null
|
||||
private var gameLayout: FrameLayout? = null
|
||||
private var gameViewRect: GameViewRectModel = GameViewRectModel()
|
||||
private var gameViewRect: GameViewInfoModel.GameViewRectModel =
|
||||
GameViewInfoModel.GameViewRectModel()
|
||||
private var roomId: String = ""
|
||||
|
||||
fun init(lifecycle: Lifecycle, gameLayout: FrameLayout) {
|
||||
private var gameContext: GameContext? = null
|
||||
|
||||
fun init(lifecycle: Lifecycle) {
|
||||
this.lifecycle = lifecycle
|
||||
this.gameLayout = gameLayout
|
||||
lifecycle.addObserver(this)
|
||||
}
|
||||
|
||||
fun setGameContext(gameContext: GameContext) {
|
||||
this.gameContext = gameContext
|
||||
}
|
||||
|
||||
fun loadGame(activity: Activity, roomId: String, gameId: Long) {
|
||||
logD("loadGame() roomId:$roomId gameId:$gameId")
|
||||
if (!this.isRunning) {
|
||||
return
|
||||
}
|
||||
@@ -85,21 +100,14 @@ open class GameEngineViewModel : BaseViewModel(), ILog, LifecycleEventObserver {
|
||||
return
|
||||
}
|
||||
val userId = AuthModel.get().currentUid.toString()
|
||||
gameFSTAPP.destroyMG()
|
||||
sudFSTAPP.destroyMG()
|
||||
val iSudFSTAPP =
|
||||
SudMGP.loadMG(activity, userId, getRoomId(), code, gameId, getGameLanguage(), gameFSMMG)
|
||||
gameFSTAPP.updateSudFSTAPP(iSudFSTAPP)
|
||||
updateGameView(iSudFSTAPP.gameView)
|
||||
SudMGP.loadMG(activity, userId, getRoomId(), code, gameId, getGameLanguage(), sudFSMMG)
|
||||
sudFSTAPP.setISudFSTAPP(iSudFSTAPP)
|
||||
gameViewLiveData.value = iSudFSTAPP.gameView
|
||||
}
|
||||
|
||||
private fun updateGameView(view: View?) {
|
||||
gameLayout?.removeAllViews()
|
||||
if (view != null) {
|
||||
gameLayout?.addView(view)
|
||||
}
|
||||
}
|
||||
|
||||
fun setGameViewRect(rect: GameViewRectModel) {
|
||||
fun setGameViewRect(rect: GameViewInfoModel.GameViewRectModel) {
|
||||
this.gameViewRect = rect
|
||||
}
|
||||
|
||||
@@ -120,40 +128,6 @@ open class GameEngineViewModel : BaseViewModel(), ILog, LifecycleEventObserver {
|
||||
}
|
||||
}
|
||||
|
||||
fun onExpireCode(handle: ISudFSMStateHandle) {
|
||||
getGameCode({
|
||||
handle.success(GameStateResponse.success().toJson())
|
||||
gameFSTAPP.updateCode(it, null)
|
||||
}, {
|
||||
logE(it)
|
||||
})
|
||||
}
|
||||
|
||||
fun onGetGameCfg(handle: ISudFSMStateHandle) {
|
||||
handle.success(JsonUtils.toJson(GameCfg()))
|
||||
}
|
||||
|
||||
fun onGetGameViewInfo(handle: ISudFSMStateHandle) {
|
||||
val gameLayout = gameLayout
|
||||
if (gameLayout == null) {
|
||||
handle.failure("gameLayout is NULL")
|
||||
return
|
||||
}
|
||||
val gameViewWidth = gameLayout.measuredWidth
|
||||
val gameViewHeight = gameLayout.measuredHeight
|
||||
if (gameViewWidth > 0 && gameViewHeight > 0) {
|
||||
notifyGameViewInfo(handle, gameViewWidth, gameViewHeight)
|
||||
return
|
||||
}
|
||||
gameLayout.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
gameLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
notifyGameViewInfo(handle, gameLayout.measuredWidth, gameLayout.measuredHeight)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun notifyGameViewInfo(handle: ISudFSMStateHandle, width: Int, height: Int) {
|
||||
val response = GameViewInfoModel()
|
||||
response.ret_code = 0
|
||||
@@ -203,4 +177,76 @@ open class GameEngineViewModel : BaseViewModel(), ILog, LifecycleEventObserver {
|
||||
lifecycle?.removeObserver(this)
|
||||
lifecycle = null
|
||||
}
|
||||
|
||||
override fun onGameStarted() {
|
||||
autoJoinGame()
|
||||
}
|
||||
|
||||
override fun onGameDestroyed() {
|
||||
}
|
||||
|
||||
private fun autoJoinGame() {
|
||||
sudFSTAPP.notifyAPPCommonSelfIn(true, -1, true, 1)
|
||||
sudFSTAPP.notifyAPPCommonSelfReady(true)
|
||||
}
|
||||
|
||||
override fun onExpireCode(handle: ISudFSMStateHandle, p1: String?) {
|
||||
getGameCode({
|
||||
handle.success(MGStateResponse.success().toJson())
|
||||
sudFSTAPP.updateCode(it, null)
|
||||
}, {
|
||||
logE(it)
|
||||
})
|
||||
}
|
||||
|
||||
override fun onGetGameViewInfo(handle: ISudFSMStateHandle, p1: String?) {
|
||||
val gameLayout = gameViewLiveData.value
|
||||
if (gameLayout == null) {
|
||||
handle.failure("gameLayout is NULL")
|
||||
return
|
||||
}
|
||||
val gameViewWidth = gameLayout.measuredWidth
|
||||
val gameViewHeight = gameLayout.measuredHeight
|
||||
if (gameViewWidth > 0 && gameViewHeight > 0) {
|
||||
notifyGameViewInfo(handle, gameViewWidth, gameViewHeight)
|
||||
return
|
||||
}
|
||||
gameLayout.viewTreeObserver.addOnGlobalLayoutListener(object :
|
||||
ViewTreeObserver.OnGlobalLayoutListener {
|
||||
override fun onGlobalLayout() {
|
||||
gameLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
|
||||
notifyGameViewInfo(handle, gameLayout.measuredWidth, gameLayout.measuredHeight)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun onGetGameCfg(handle: ISudFSMStateHandle, p1: String?) {
|
||||
handle.success(JsonUtils.toJson(GameCfg()))
|
||||
}
|
||||
|
||||
override fun onGameMGCommonSelfClickJoinBtn(
|
||||
handle: ISudFSMStateHandle?,
|
||||
model: SudMGPMGState.MGCommonSelfClickJoinBtn?
|
||||
) {
|
||||
sudFSTAPP.notifyAPPCommonSelfIn(true, -1, true, 1)
|
||||
}
|
||||
|
||||
override fun onPlayerMGCommonPlayerReady(
|
||||
handle: ISudFSMStateHandle?,
|
||||
userId: String?,
|
||||
model: SudMGPMGState.MGCommonPlayerReady?
|
||||
) {
|
||||
super.onPlayerMGCommonPlayerReady(handle, userId, model)
|
||||
val queueAbility =
|
||||
gameContext?.findAbility<GameQueueAbility>(GameQueueAbility::class.java.simpleName)
|
||||
?: return
|
||||
val queueSize = queueAbility.queueFlow.value?.size ?: 0
|
||||
if (queueSize == 0) {
|
||||
return
|
||||
}
|
||||
logD("onPlayerMGCommonPlayerReady queueSize:$queueSize size:${sudFSMMG.sudFSMMGCache.playerReadySet.size}")
|
||||
if (sudFSMMG.sudFSMMGCache.playerReadySet.size >= queueSize) {
|
||||
sudFSTAPP.notifyAPPCommonSelfPlaying(true, null, null)
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,48 +0,0 @@
|
||||
package com.chwl.app.game.core.engine
|
||||
|
||||
import com.chwl.app.game.core.engine.model.GameStateResponse
|
||||
import com.example.lib_utils.log.ILog
|
||||
import tech.sud.mgp.core.ISudFSMMG
|
||||
import tech.sud.mgp.core.ISudFSMStateHandle
|
||||
|
||||
class GameSudFSMMG(private val engineViewModel: GameEngineViewModel) : ISudFSMMG, ILog {
|
||||
override fun onGameLog(p0: String?) {
|
||||
if (p0 != null) {
|
||||
logD(p0)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGameLoadingProgress(p0: Int, p1: Int, p2: Int) {
|
||||
}
|
||||
|
||||
override fun onGameStarted() {
|
||||
}
|
||||
|
||||
override fun onGameDestroyed() {
|
||||
}
|
||||
|
||||
override fun onExpireCode(p0: ISudFSMStateHandle, p1: String?) {
|
||||
engineViewModel.onExpireCode(p0)
|
||||
}
|
||||
|
||||
override fun onGetGameViewInfo(p0: ISudFSMStateHandle, p1: String?) {
|
||||
engineViewModel.onGetGameViewInfo(p0)
|
||||
}
|
||||
|
||||
override fun onGetGameCfg(p0: ISudFSMStateHandle, p1: String?) {
|
||||
engineViewModel.onGetGameCfg(p0)
|
||||
}
|
||||
|
||||
override fun onGameStateChange(p0: ISudFSMStateHandle, p1: String?, p2: String?) {
|
||||
p0.success(GameStateResponse.success().toJson())
|
||||
}
|
||||
|
||||
override fun onPlayerStateChange(
|
||||
p0: ISudFSMStateHandle,
|
||||
p1: String?,
|
||||
p2: String?,
|
||||
p3: String?
|
||||
) {
|
||||
p0.success(GameStateResponse.success().toJson())
|
||||
}
|
||||
}
|
@@ -1,37 +0,0 @@
|
||||
package com.chwl.app.game.core.engine
|
||||
|
||||
import tech.sud.mgp.core.ISudFSTAPP
|
||||
import tech.sud.mgp.core.ISudListenerNotifyStateChange
|
||||
|
||||
class GameSudFSTAPP(private val engineViewModel: GameEngineViewModel) {
|
||||
private var sudFSTAPP: ISudFSTAPP? = null
|
||||
|
||||
fun updateSudFSTAPP(iSudFSTAPP: ISudFSTAPP) {
|
||||
this.sudFSTAPP = iSudFSTAPP
|
||||
}
|
||||
|
||||
fun updateCode(code: String, listener: ISudListenerNotifyStateChange?) {
|
||||
this.sudFSTAPP?.updateCode(code, listener)
|
||||
}
|
||||
|
||||
fun startMG() {
|
||||
this.sudFSTAPP?.startMG()
|
||||
}
|
||||
|
||||
fun playMG() {
|
||||
this.sudFSTAPP?.playMG()
|
||||
}
|
||||
|
||||
fun pauseMG() {
|
||||
this.sudFSTAPP?.pauseMG()
|
||||
}
|
||||
|
||||
fun stopMG() {
|
||||
this.sudFSTAPP?.stopMG()
|
||||
}
|
||||
|
||||
fun destroyMG() {
|
||||
sudFSTAPP?.destroyMG()
|
||||
sudFSTAPP = null
|
||||
}
|
||||
}
|
@@ -1,25 +0,0 @@
|
||||
package com.chwl.app.game.core.engine.model
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.chwl.library.utils.json.JsonUtils
|
||||
import java.io.Serializable
|
||||
|
||||
@Keep
|
||||
data class GameStateResponse(
|
||||
var ret_code: Int = CODE_SUCCESS, // 返回码
|
||||
var ret_msg: String? = null // 返回消息
|
||||
) : Serializable {
|
||||
|
||||
fun toJson(): String {
|
||||
return JsonUtils.toJson(this)
|
||||
}
|
||||
|
||||
// 返回码,成功
|
||||
companion object {
|
||||
val CODE_SUCCESS = 0
|
||||
|
||||
fun success(): GameStateResponse {
|
||||
return GameStateResponse(CODE_SUCCESS, "success")
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright © Sud.Tech
|
||||
* https://sud.tech
|
||||
*/
|
||||
|
||||
package com.chwl.app.game.core.engine.model;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
/**
|
||||
* 游戏视图
|
||||
* 参考文档:https://docs.sud.tech/zh-CN/app/Client/API/ISudFSMMG/onGetGameViewInfo.html
|
||||
*/
|
||||
@Keep
|
||||
public class GameViewInfoModel {
|
||||
// 返回码
|
||||
public int ret_code;
|
||||
|
||||
// 返回消息
|
||||
public String ret_msg;
|
||||
|
||||
// 游戏View的大小
|
||||
public GameViewSizeModel view_size = new GameViewSizeModel();
|
||||
|
||||
// 游戏安全操作区域
|
||||
public GameViewRectModel view_game_rect = new GameViewRectModel();
|
||||
@Keep
|
||||
public static class GameViewSizeModel {
|
||||
// 游戏View的宽 (单位像素)
|
||||
public int width;
|
||||
|
||||
// 游戏View的高 (单位像素)
|
||||
public int height;
|
||||
}
|
||||
@Keep
|
||||
public static class GameViewRectModel {
|
||||
// 相对于view_size左边框偏移(单位像素)
|
||||
public int left;
|
||||
// 相对于view_size上边框偏移(单位像素)
|
||||
public int top;
|
||||
// 相对于view_size右边框偏移(单位像素)
|
||||
public int right;
|
||||
// 相对于view_size下边框偏移(单位像素)
|
||||
public int bottom;
|
||||
}
|
||||
|
||||
}
|
@@ -1,7 +1,7 @@
|
||||
package com.chwl.app.game.data
|
||||
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.app.game.data.bean.GameRoomInfo
|
||||
import com.chwl.core.bean.game.GameConfigBean
|
||||
import com.chwl.core.bean.game.GameRoomInfo
|
||||
import com.chwl.core.base.BaseModel
|
||||
import com.chwl.core.bean.response.ServiceResult
|
||||
import com.chwl.core.bean.room.BaseRoomInfo
|
||||
@@ -33,11 +33,16 @@ object GameModel2 : BaseModel() {
|
||||
api.startGame(gameId, gameMode)
|
||||
}
|
||||
|
||||
suspend fun closeGame(roomId: Long): String? =
|
||||
launchRequest {
|
||||
api.closeGame(roomId)
|
||||
}
|
||||
|
||||
private interface Api {
|
||||
/**
|
||||
* 房间信息
|
||||
*/
|
||||
@GET("chatRoom/get")
|
||||
@GET("chatRoom/getByType")
|
||||
suspend fun getChatRoomInfo(@Query("roomType") roomType: Int): ServiceResult<GameRoomInfo>
|
||||
|
||||
/**
|
||||
@@ -55,6 +60,12 @@ object GameModel2 : BaseModel() {
|
||||
@Field("mgId") mgId: String,
|
||||
@Field("gameMode") gameMode: Int
|
||||
): ServiceResult<Long>
|
||||
|
||||
/**
|
||||
* 关闭游戏
|
||||
*/
|
||||
@GET("miniGame/nav/close")
|
||||
suspend fun closeGame(@Query("roomId") roomId: Long): ServiceResult<String>
|
||||
}
|
||||
|
||||
}
|
@@ -1,12 +0,0 @@
|
||||
package com.chwl.app.game.data.bean
|
||||
|
||||
import androidx.annotation.Keep
|
||||
|
||||
@Keep
|
||||
class GameConfigBean {
|
||||
val mgId: Long? = null
|
||||
val mgIdStr: String? = null
|
||||
val name: String? = null
|
||||
val pic: String? = null
|
||||
val gameModes: List<GameModeBean>? = null
|
||||
}
|
@@ -0,0 +1,15 @@
|
||||
package com.chwl.app.game.data.bean
|
||||
|
||||
import com.chwl.core.bean.game.GameRoomInfo
|
||||
|
||||
|
||||
sealed class GameInfoUiState {
|
||||
|
||||
object Loading : GameInfoUiState()
|
||||
|
||||
object Success : GameInfoUiState()
|
||||
|
||||
data class Failed(val throwable: Throwable, val gameInfo: GameRoomInfo?) : GameInfoUiState()
|
||||
|
||||
data class Empty(val gameInfo: GameRoomInfo?) : GameInfoUiState()
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
package com.chwl.app.game.data.bean
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import java.io.Serializable
|
||||
|
||||
@Keep
|
||||
class GameModeBean : Serializable {
|
||||
val ticket: Long? = null
|
||||
val modeIcon: String? = null
|
||||
val gameMode: Int? = null
|
||||
val scores: List<Int>? = null
|
||||
val ruleUrl: String? = null
|
||||
val modeName: String? = null
|
||||
}
|
@@ -1,18 +0,0 @@
|
||||
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
|
||||
}
|
@@ -1,8 +0,0 @@
|
||||
package com.chwl.app.game.data.bean
|
||||
|
||||
import androidx.annotation.Keep
|
||||
import com.chwl.core.bean.room.BaseRoomInfo
|
||||
|
||||
@Keep
|
||||
class GameRoomInfo : BaseRoomInfo<GameRoomData>() {
|
||||
}
|
@@ -12,8 +12,8 @@ import androidx.lifecycle.repeatOnLifecycle
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.common.widget.dialog.DialogManager
|
||||
import com.chwl.app.databinding.GameBuyDialogBinding
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.app.game.data.bean.GameModeBean
|
||||
import com.chwl.core.bean.game.GameConfigBean
|
||||
import com.chwl.core.bean.game.GameModeBean
|
||||
import com.chwl.app.game.ui.game.GameActivity
|
||||
import com.chwl.app.game.ui.game.GameIntent
|
||||
import com.chwl.app.game.ui.home.GameHomeViewModel
|
||||
|
@@ -2,6 +2,8 @@ package com.chwl.app.game.ui.game
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.FrameLayout
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.common.widget.dialog.DialogManager.OkCancelDialogListener
|
||||
@@ -9,18 +11,17 @@ 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.sud.model.GameViewInfoModel
|
||||
import com.chwl.core.support.room.RoomView
|
||||
import com.example.lib_utils.ktx.getColorById
|
||||
import com.example.lib_utils.ktx.singleClick
|
||||
import com.example.lib_utils.log.ILog
|
||||
import com.example.lib_utils.spannable.SpannableTextBuilder
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.zip
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
@@ -41,14 +42,13 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
return
|
||||
}
|
||||
super.init()
|
||||
initGameEngine()
|
||||
viewModel.init(intentData)
|
||||
}
|
||||
|
||||
private fun initGameEngine() {
|
||||
gameEngineViewModel.init(lifecycle, binding.layoutGame)
|
||||
override fun initView() {
|
||||
super.initView()
|
||||
binding.spaceGameRect.post {
|
||||
val rect = GameViewRectModel().apply {
|
||||
val rect = GameViewInfoModel.GameViewRectModel().apply {
|
||||
top = binding.spaceGameRect.top
|
||||
bottom = binding.root.height - binding.spaceGameRect.bottom
|
||||
}
|
||||
@@ -65,14 +65,8 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
}
|
||||
}
|
||||
|
||||
override fun initObserver() {
|
||||
super.initObserver()
|
||||
viewModel.gameContextLiveData.observe(this) {
|
||||
updateGameContext(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateGameContext(gameContext: GameContext) {
|
||||
override fun onGameContext(gameContext: GameContext) {
|
||||
super.onGameContext(gameContext)
|
||||
val stateAbility =
|
||||
gameContext.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
|
||||
?: return
|
||||
@@ -80,30 +74,49 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
stateAbility.gameIconFlow.collectLatest {
|
||||
binding.ivLogo.loadImage(it)
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
stateAbility.scoresFlow.collectLatest {
|
||||
val number = it?.first()?.toString() ?: ""
|
||||
binding.tvAwardValue.text = number
|
||||
binding.tvAwardTips.text = getString(R.string.game_award_tips_format, number)
|
||||
updateAward(it?.first())
|
||||
}
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
stateAbility.matchFailedFlow.collectLatest {
|
||||
showMatchFailed()
|
||||
}
|
||||
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
|
||||
private fun updateAward(number: Double?) {
|
||||
val numberStr = number?.toInt()?.toString() ?: ""
|
||||
if (numberStr.isEmpty()) {
|
||||
binding.layoutAward.isVisible = false
|
||||
binding.tvAwardTips.isVisible = false
|
||||
} else {
|
||||
binding.layoutAward.isVisible = true
|
||||
binding.tvAwardTips.isVisible = true
|
||||
binding.tvAwardValue.text = numberStr
|
||||
val awardTips = getString(R.string.game_award_tips_format, numberStr)
|
||||
SpannableTextBuilder(binding.tvAwardTips).appendText(awardTips)
|
||||
.setTextStyle(numberStr, textColor = getColorById(R.color.color_FF6629)).apply()
|
||||
}
|
||||
}
|
||||
|
||||
override fun initObserver() {
|
||||
super.initObserver()
|
||||
lifecycleScope.launch {
|
||||
viewModel.closeRoomFlow.collectLatest {
|
||||
loadingDialogManager?.dismissDialog()
|
||||
finish()
|
||||
}
|
||||
}.collectLatest {
|
||||
if (it != null) {
|
||||
gameEngineViewModel.loadGame(
|
||||
this@GameActivity,
|
||||
it.second.toString(),
|
||||
it.first
|
||||
)
|
||||
}
|
||||
|
||||
lifecycleScope.launch {
|
||||
viewModel.restartFlow.collectLatest {
|
||||
loadingDialogManager?.dismissDialog()
|
||||
// TODO 待完善
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,17 +133,41 @@ class GameActivity : BaseGameActivity<GameActivityBinding>(), RoomView, ILog {
|
||||
showExitTips()
|
||||
}
|
||||
|
||||
private fun showExitTips() {
|
||||
dialogManager.showOkCancelDialog(
|
||||
getString(R.string.game_exit_tips),
|
||||
getString(R.string.layout_dialog_game_exit_04),
|
||||
getString(R.string.exit_text), object : OkCancelDialogListener {
|
||||
override fun getGameViewGroup(): FrameLayout {
|
||||
return binding.layoutGame
|
||||
}
|
||||
|
||||
private fun showMatchFailed() {
|
||||
dialogManager.showOkCancelDialog(null,
|
||||
getString(R.string.game_match_failed),
|
||||
getString(R.string.game_rematch),
|
||||
getString(R.string.exit_text), false, false, object : OkCancelDialogListener {
|
||||
override fun onOk() {
|
||||
loadingDialogManager?.showProgressDialog(this@GameActivity)
|
||||
viewModel.restart()
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
super.onCancel()
|
||||
this@GameActivity.finish()
|
||||
loadingDialogManager?.showProgressDialog(this@GameActivity)
|
||||
viewModel.closeRoom()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun showExitTips() {
|
||||
dialogManager.showOkCancelDialog(null,
|
||||
getString(R.string.game_exit_tips),
|
||||
getString(R.string.layout_dialog_game_exit_04),
|
||||
getString(R.string.exit_text), false, false, object : OkCancelDialogListener {
|
||||
override fun onOk() {
|
||||
dialogManager.dismissDialog()
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
super.onCancel()
|
||||
loadingDialogManager?.showProgressDialog(this@GameActivity)
|
||||
viewModel.closeRoom()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@@ -1,14 +1,26 @@
|
||||
package com.chwl.app.game.ui.game
|
||||
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.core.GameContext
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.core.bean.response.BeanResult
|
||||
import com.chwl.library.utils.ResUtil
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
||||
class GameViewModel : BaseViewModel() {
|
||||
|
||||
val gameContextLiveData = MutableLiveData<GameContext>()
|
||||
|
||||
val closeRoomFlow = MutableSharedFlow<BeanResult<String?>>()
|
||||
|
||||
val restartFlow = MutableSharedFlow<BeanResult<String?>>()
|
||||
|
||||
private var gameIntent: GameIntent? = null
|
||||
|
||||
fun init(intent: GameIntent) {
|
||||
this.gameIntent = intent
|
||||
val gameContext = GameContext(intent.roomId)
|
||||
gameContext.performStart()
|
||||
gameContextLiveData.value = gameContext
|
||||
@@ -18,4 +30,34 @@ class GameViewModel : BaseViewModel() {
|
||||
super.onCleared()
|
||||
gameContextLiveData.value?.performStop()
|
||||
}
|
||||
|
||||
fun restart() {
|
||||
val intent = gameIntent
|
||||
if (intent == null) {
|
||||
safeLaunch {
|
||||
restartFlow.emit(BeanResult.failed(NullPointerException(ResUtil.getString(R.string.utils_net_beanobserver_05))))
|
||||
}
|
||||
return
|
||||
}
|
||||
safeLaunch {
|
||||
val result = GameModel2.startGame(intent.gameId.toString(), intent.gameMode)
|
||||
// TODO 待完善
|
||||
}
|
||||
}
|
||||
|
||||
fun closeRoom() {
|
||||
val roomId = gameContextLiveData.value?.roomId
|
||||
if (roomId != null) {
|
||||
safeLaunch(onError = {
|
||||
closeRoomFlow.emit(BeanResult.failed(it))
|
||||
}) {
|
||||
GameModel2.closeGame(roomId)
|
||||
closeRoomFlow.emit(BeanResult.success(null))
|
||||
}
|
||||
} else {
|
||||
safeLaunch {
|
||||
closeRoomFlow.emit(BeanResult.success(null))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -6,7 +6,15 @@ import android.view.LayoutInflater
|
||||
import androidx.databinding.DataBindingUtil
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.databinding.GameQueueWidgetBinding
|
||||
import com.chwl.app.game.core.GameQueueAbility
|
||||
import com.chwl.app.game.core.GameStateAbility
|
||||
import com.chwl.app.ui.utils.loadAvatar
|
||||
import com.chwl.core.auth.AuthModel
|
||||
import com.chwl.core.bean.room.RoomMicBean
|
||||
import com.chwl.core.support.room.FrameLayoutRoomWidget
|
||||
import com.chwl.core.support.room.RoomContext
|
||||
import com.chwl.core.support.room.RoomView
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
|
||||
class GameQueueWidget : FrameLayoutRoomWidget {
|
||||
|
||||
@@ -32,11 +40,52 @@ class GameQueueWidget : FrameLayoutRoomWidget {
|
||||
defStyleRes: Int
|
||||
) : super(context, attrs, defStyleAttr, defStyleRes)
|
||||
|
||||
init {
|
||||
binding.tvState.setText("AAAA")
|
||||
override fun onInitialize(roomView: RoomView, roomContext: RoomContext) {
|
||||
super.onInitialize(roomView, roomContext)
|
||||
val stateAbility =
|
||||
roomContext.findAbility<GameStateAbility>(GameStateAbility::class.java.simpleName)
|
||||
val queueAbility =
|
||||
roomContext.findAbility<GameQueueAbility>(GameQueueAbility::class.java.simpleName)
|
||||
queueAbility?.let {
|
||||
safeLaunch {
|
||||
it.queueFlow.collectLatest {
|
||||
updateQueue(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
stateAbility?.let {
|
||||
safeLaunch {
|
||||
it.gameStateFlow.collectLatest {
|
||||
updateState(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateState() {
|
||||
private fun updateQueue(list: List<RoomMicBean>?) {
|
||||
val selfInfo = list?.firstOrNull {
|
||||
it.micUser?.uid == AuthModel.get().currentUid
|
||||
}
|
||||
|
||||
val targetInfo = list?.firstOrNull {
|
||||
it.micUser?.uid != AuthModel.get().currentUid
|
||||
}
|
||||
|
||||
binding.ivQueue1.loadAvatar(selfInfo?.micUser?.avatar)
|
||||
binding.ivQueue2.loadAvatar(targetInfo?.micUser?.avatar)
|
||||
}
|
||||
|
||||
private fun updateState(gameState: Int?) {
|
||||
when (gameState) {
|
||||
1, 2 -> {
|
||||
binding.tvState.setText(R.string.match_successfully)
|
||||
binding.ivState.setImageResource(R.drawable.game_ic_vs)
|
||||
}
|
||||
|
||||
else -> {
|
||||
binding.tvState.setText(R.string.matchmaking)
|
||||
binding.ivState.setImageResource(R.drawable.game_ic_link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -4,7 +4,7 @@ import android.widget.ImageView
|
||||
import com.chad.library.adapter.base.BaseQuickAdapter
|
||||
import com.chad.library.adapter.base.BaseViewHolder
|
||||
import com.chwl.app.R
|
||||
import com.chwl.app.game.data.bean.GameModeBean
|
||||
import com.chwl.core.bean.game.GameModeBean
|
||||
import com.chwl.app.ui.utils.load
|
||||
|
||||
class GameHomeAdapter : BaseQuickAdapter<GameModeBean, BaseViewHolder>(R.layout.game_home_item) {
|
||||
|
@@ -4,7 +4,7 @@ import androidx.fragment.app.activityViewModels
|
||||
import com.chwl.app.MainTabContentView
|
||||
import com.chwl.app.base.BaseViewBindingFragment
|
||||
import com.chwl.app.databinding.GameHomeFragmentBinding
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.core.bean.game.GameConfigBean
|
||||
import com.chwl.app.game.ui.buy.GameBuyDialog
|
||||
import com.chwl.app.support.FragmentVisibleStateHelper
|
||||
import com.chwl.app.ui.pay.ChargeActivity
|
||||
|
@@ -3,7 +3,7 @@ package com.chwl.app.game.ui.home
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.chwl.app.base.BaseViewModel
|
||||
import com.chwl.app.game.data.GameModel2
|
||||
import com.chwl.app.game.data.bean.GameConfigBean
|
||||
import com.chwl.core.bean.game.GameConfigBean
|
||||
import com.chwl.core.bean.response.BeanResult
|
||||
import com.chwl.core.pay.PayModel
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
@@ -60,10 +60,12 @@
|
||||
android:layout_marginTop="@dimen/dp_9"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_14"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/queue_widget"
|
||||
tools:text="@string/game_award_tips_format" />
|
||||
tools:text="@string/game_award_tips_format"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/layout_award"
|
||||
@@ -71,8 +73,10 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dp_21"
|
||||
android:layout_marginTop="@dimen/dp_22"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_award_tips">
|
||||
app:layout_constraintTop_toBottomOf="@id/tv_award_tips"
|
||||
tools:visibility="visible">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
@@ -89,7 +93,6 @@
|
||||
android:minWidth="@dimen/dp_56"
|
||||
android:paddingStart="@dimen/dp_10"
|
||||
android:paddingEnd="@dimen/dp_10"
|
||||
android:text="0"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="@dimen/dp_17" />
|
||||
</FrameLayout>
|
||||
|
@@ -1,8 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="matchmaking">匹配中</string>
|
||||
<string name="match_successfully">匹配成功</string>
|
||||
<string name="game_award_tips_format">獲勝獎勵%s金幣</string>
|
||||
<string name="start">开始</string>
|
||||
<string name="game_ticket_format">入场费(%s)</string>
|
||||
<string name="game_exit_tips">遊戲已經開始,退出房間將默認遊戲失敗,確認退出房間?</string>
|
||||
<string name="game_match_failed">匹配失敗,是否重新開始?</string>
|
||||
<string name="game_rematch">重新匹配</string>
|
||||
</resources>
|
@@ -2,8 +2,11 @@
|
||||
<resources>
|
||||
|
||||
<string name="matchmaking">匹配中</string>
|
||||
<string name="match_successfully">匹配成功</string>
|
||||
<string name="game_award_tips_format">獲勝獎勵%s金幣</string>
|
||||
<string name="start">開始</string>
|
||||
<string name="game_ticket_format">入场费(%s)</string>
|
||||
<string name="game_exit_tips">遊戲已經開始,退出房間將默認遊戲失敗,確認退出房間?</string>
|
||||
<string name="game_match_failed">匹配失敗,是否重新開始?</string>
|
||||
<string name="game_rematch">重新匹配</string>
|
||||
</resources>
|
@@ -1,8 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="matchmaking">匹配中</string>
|
||||
<string name="match_successfully">匹配成功</string>
|
||||
<string name="game_award_tips_format">獲勝獎勵%s金幣</string>
|
||||
<string name="start">开始</string>
|
||||
<string name="game_ticket_format">入场费(%s)</string>
|
||||
<string name="game_exit_tips">遊戲已經開始,退出房間將默認遊戲失敗,確認退出房間?</string>
|
||||
<string name="game_match_failed">匹配失敗,是否重新開始?</string>
|
||||
<string name="game_rematch">重新匹配</string>
|
||||
</resources>
|
Reference in New Issue
Block a user