[Modify]游戏房接入

This commit is contained in:
wushaocheng
2023-09-05 14:29:57 +08:00
parent ef8ca0b939
commit 877c3d9361
11 changed files with 1394 additions and 1 deletions

View File

@@ -6,6 +6,9 @@ apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.tencent.vasdolly' apply plugin: 'com.tencent.vasdolly'
apply from: '../mob.gradle' apply from: '../mob.gradle'
configurations.maybeCreate("default")
artifacts.add("default", file('SudMGP-v1.1.52.554.aar'))
def onlyArm64 = Boolean.parseBoolean(only_arm64) def onlyArm64 = Boolean.parseBoolean(only_arm64)
android { android {

Binary file not shown.

View File

@@ -0,0 +1,196 @@
package com.yizhuan.erban.avroom.fragment
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.databinding.DataBindingUtil
import com.yizhuan.erban.R
import com.yizhuan.erban.avroom.adapter.GameMicroViewAdapter
import com.yizhuan.erban.avroom.adapter.GameMiniMicroViewAdapter
import com.yizhuan.erban.avroom.adapter.OnMicroItemClickListener
import com.yizhuan.erban.avroom.firstcharge.FirstChargePrizeDialog
import com.yizhuan.erban.avroom.game.GameDelegate
import com.yizhuan.erban.avroom.game.OnGameStatusChangeListener
import com.yizhuan.erban.avroom.presenter.GameRoomPresenter
import com.yizhuan.erban.avroom.view.IGameRoomView
import com.yizhuan.erban.databinding.FragmentGameRoomBinding
import com.yizhuan.erban.ui.widget.GiftDialog.OnGiftDialogBtnClickListener
import com.yizhuan.xchat_android_core.home.bean.BannerInfo
import com.yizhuan.xchat_android_core.manager.AvRoomDataManager
import com.yizhuan.xchat_android_core.music.model.PlayerModel
import com.yizhuan.xchat_android_core.pay.event.FirstChargeEvent
import com.yizhuan.xchat_android_core.room.event.FinishAvRoomEvent
import com.yizhuan.xchat_android_library.base.factory.CreatePresenter
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
/**
* 轰趴房间
*
* @author chenran
* @date 2017/7/26
*/
@CreatePresenter(GameRoomPresenter::class)
class GameRoomFragment : BaseRoomFragment<IGameRoomView?, GameRoomPresenter?>(),
View.OnClickListener, OnGiftDialogBtnClickListener, IGameRoomView, OnMicroItemClickListener,
OnGameStatusChangeListener {
companion object {
@JvmStatic
fun newInstance(): GameRoomFragment {
val roomFragment = GameRoomFragment()
val bundle = Bundle()
roomFragment.arguments = bundle
return roomFragment
}
}
private lateinit var gameBinding: FragmentGameRoomBinding
private lateinit var gameDelegate: GameDelegate
private var isShowMiniMic = false
override fun getRootLayoutId(): Int {
return R.layout.fragment_game_room
}
override fun onFindViews() {
super.onFindViews()
gameBinding = DataBindingUtil.bind(mView)!!
gameBinding.lifecycleOwner = this
gameBinding.click = this
gameBinding.ktvModel = false
gameDelegate = GameDelegate(
requireActivity(),
gameBinding.flGameContainer,
AvRoomDataManager.get().mCurrentRoomInfo?.mgId
)
gameDelegate.setOnGameStatusChangeListener(this)
}
@SuppressLint("CheckResult")
override fun initiate() {
gameBinding.microView.bindAdapter(GameMicroViewAdapter(context))
super.initiate()
//游戏模式暂时不需要这个
PlayerModel.get().stop()
gameBinding.roomInfo = AvRoomDataManager.get().mCurrentRoomInfo
mvpPresenter?.getBannerList()
gameBinding.tvShowMiniMic.setOnClickListener { showMiniMic() }
gameBinding.ivShowMic.setOnClickListener { showMic() }
}
private fun showMiniMic() {
if (isShowMiniMic) return
isShowMiniMic = true
gameBinding.microView.bindAdapter(GameMiniMicroViewAdapter(context).apply {
setOnClick { showMic() }
})
gameBinding.tvShowMiniMic.isVisible = false
gameBinding.microView.postDelayed({
gameBinding.ivShowMic.isVisible = true
gameBinding.llMicView.setBackgroundResource(R.drawable.bg_mini_mic_entrance)
}, 100)
}
private fun showMic() {
if (!isShowMiniMic) return
isShowMiniMic = false
gameBinding.microView.bindAdapter(GameMicroViewAdapter(context))
gameBinding.tvShowMiniMic.isVisible = true
gameBinding.llMicView.background = null
gameBinding.ivShowMic.isVisible = false
}
override fun onSetListener() {
super.onSetListener()
bottomView.setBottomViewListener(BaseRoomBottomViewWrapper())
}
override fun updateView() {
super.updateView()
gameDelegate.updateGame(AvRoomDataManager.get().mCurrentRoomInfo?.mgId)
gameBinding.roomInfo = AvRoomDataManager.get().mCurrentRoomInfo
if (isSixMic()) {
gameBinding.tvShowMiniMic.isVisible = !isShowMiniMic
gameBinding.ivShowMic.isVisible = isShowMiniMic
} else {
showMic()
gameBinding.tvShowMiniMic.isInvisible = true
gameBinding.ivShowMic.isVisible = false
}
gameBinding.microView.adapter.notifyDataSetChanged()
}
override fun onGameStart() {
if (isSixMic()) {
showMiniMic()
}
}
override fun onGameEnd() {
if (isSixMic()) {
showMic()
}
}
private fun isSixMic(): Boolean {
return AvRoomDataManager.get().mgMicNum == AvRoomDataManager.GAME_DEF_MIC_COUNT
}
override fun onSendMsgSuccess(msg: String?) {
super.onSendMsgSuccess(msg)
msg?.let {
if (AvRoomDataManager.get().isSelfGamePlaying) {
gameDelegate.hitTheMark(msg)
}
}
}
override fun onShowBanner(dialogInfos: List<BannerInfo>) {
initRoomAct(gameBinding.activityImg, dialogInfos)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onFinishAvRoomEvent(event: FinishAvRoomEvent) {
gameDelegate.exitGame()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onFirstRechargeEvent(event: FirstChargeEvent) {
FirstChargePrizeDialog(
requireContext(),
event.chargeProdTitle,
event.firstChargeRewardList
).openDialog()
}
override fun onStart() {
super.onStart()
gameDelegate.onStart()
}
override fun onResume() {
super.onResume()
gameDelegate.onResume()
}
override fun onPause() {
super.onPause()
gameDelegate.onPause()
}
override fun onStop() {
super.onStop()
gameDelegate.onStop()
}
override fun onDestroy() {
gameDelegate.onDestroy()
super.onDestroy()
}
}

View File

@@ -434,7 +434,9 @@ public class HomePartyFragment extends BaseFragment implements View.OnClickListe
Fragment tempFragment = roomFragment; Fragment tempFragment = roomFragment;
switch (currentRoomInfo.getType()) { switch (currentRoomInfo.getType()) {
case RoomInfo.ROOMTYPE_GAME: case RoomInfo.ROOMTYPE_GAME:
toast(getString(R.string.room_game_is_not_open_yet)); if (!(tempFragment instanceof GameRoomFragment)) {
tempFragment = GameRoomFragment.newInstance();
}
break; break;
case RoomInfo.ROOM_TYPE_SINGLE: case RoomInfo.ROOM_TYPE_SINGLE:
if (!(tempFragment instanceof SingleRoomFragment)) { if (!(tempFragment instanceof SingleRoomFragment)) {

View File

@@ -0,0 +1,15 @@
/*
Copyright © Sud.Tech
https://sud.tech
*/
package com.yizhuan.erban.avroom.game;
import com.yizhuan.xchat_android_library.BuildConfig;
public class AppConfig {
protected static final String APP_ID = "1578948593831571457";
protected static final String APP_KEY = "J9lHOXvFWkAZiTfl4SK7IGt0wDnW3fWd";
protected static boolean isTestEnv = BuildConfig.DEBUG;
}

View File

@@ -0,0 +1,671 @@
package com.yizhuan.erban.avroom.game
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.text.TextUtils
import android.util.Log
import android.view.View
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.FrameLayout
import com.google.gson.Gson
import com.netease.nim.uikit.common.util.sys.ScreenUtil
import com.yizhuan.xchat_android_core.auth.AuthModel
import com.yizhuan.xchat_android_core.manager.AvRoomDataManager
import com.yizhuan.xchat_android_core.room.game.GameCfg
import com.yizhuan.xchat_android_core.room.game.GameModel
import com.yizhuan.xchat_android_core.room.game.GameStatus
import com.yizhuan.xchat_android_core.room.model.HomePartyModel
import com.yizhuan.xchat_android_core.user.UserModel
import com.yizhuan.xchat_android_core.utils.LogUtils
import com.yizhuan.xchat_android_core.utils.net.RxHelper
import com.yizhuan.xchat_android_library.net.rxnet.callback.CallBack
import com.yizhuan.xchat_android_library.utils.SingleToastUtil
import okhttp3.*
import org.json.JSONException
import org.json.JSONObject
import tech.sud.mgp.core.*
import java.util.*
class GameDelegate(val activity: Activity, val container: FrameLayout, var mgId: Long?) {
private val TAG = "GameDelegate"
private var APP_CODE = ""
private val mRoomID = AvRoomDataManager.get().roomUid.toString()
private val mLanguage = "zh-TW" //語言
//調用遊戲SDK的接口,成功加載遊戲後可用:
private var iSudFSTAPP: ISudFSTAPP? = null
private val gson = Gson()
//小遊戲ID
private var mMGID = 0L
//通用狀態-遊戲,關鍵詞
private var mKeyWord: String? = null
private val mUid = AuthModel.get().currentUid.toString()
private val homePartyModel = HomePartyModel()
private var onGameStatusChangeListener: OnGameStatusChangeListener? = null
fun setOnGameStatusChangeListener(onGameStatusChangeListener: OnGameStatusChangeListener) {
this.onGameStatusChangeListener = onGameStatusChangeListener
}
private val loginCallback: AppLoginListener =
object : AppLoginListener {
override fun onLoginFailure(err: String?) {
SingleToastUtil.showToast(err)
}
override fun onLoginSuccess(new_code: String, expire_Date: Long) {
APP_CODE = new_code
Handler(Looper.getMainLooper()).post {
//初始化遊戲SDK
initGameSDK(
activity,
AppConfig.APP_ID,
AppConfig.APP_KEY,
AppConfig.isTestEnv
)
}
}
}
init {
mMGID = mgId ?: 0L
login(loginCallback)
}
fun updateGame(mgId: Long?) {
if (mgId == null || mgId == 0L || mgId == mMGID || iSudFSTAPP == null) return
mMGID = mgId
updateMyMicQueue(GameStatus.STATUS_NOT_JOIN)
loadMG(activity, mUid, mRoomID, APP_CODE, mMGID, mLanguage)
}
fun exitGame() {
UserModel.get().cacheLoginUserInfo?.gameStatus = GameStatus.STATUS_NOT_JOIN
notifySelfPlayingState(false)
notifySelfInState(false)
}
/**
* 例如"你畫我猜"遊戲的文字命中
*/
fun hitTheMark(msg: String) {
mKeyWord?.let {
if (msg.contains(it)) {
notifySelfTextHit(it, msg)
}
}
}
/**
* "接入方客戶端"登陸接口, 從"接入方服務端"獲得Code
* "接入方服務端"是通過"服務端接入SDK"獲得Code來返回給"接入方客戶端"的
* @param listener
*/
@SuppressLint("CheckResult")
private fun login(listener: AppLoginListener) {
GameModel.getGameCode()
.compose(RxHelper.bindContext(activity))
.subscribe({
listener.onLoginSuccess(it.code, it.expireDate)
}, {
listener.onLoginFailure(it.message)
})
}
/**
* 1初始化遊戲SDK
*
* @param context 上下文
* @param appID appID
* @param appKey appKey
* @param isTestEnv 是否是測試環境true測試環境false正式環境
*/
private fun initGameSDK(context: Context, appID: String, appKey: String, isTestEnv: Boolean) {
SudMGP.initSDK(context, appID, appKey, isTestEnv, object : ISudListenerInitSDK {
override fun onSuccess() {
loadMG(activity, mUid, mRoomID, APP_CODE, mMGID, mLanguage)
}
override fun onFailure(code: Int, errInfo: String) {
showToast("初始化遊戲SDK失敗:$code--errInfo:$errInfo")
}
})
}
/**
* 2加載遊戲
*
* @param activity 上下文Activity
* @param userID 用戶ID業務系統保證每個用戶擁有唯一ID
* @param roomID 房間ID進入同一房間內的
* @param code 令牌
* @param mgID 小遊戲ID
* @param language 遊戲語言 現支持簡體zh-CN 繁體zh-TW 英語en-US 馬來語ms-MY
*/
private fun loadMG(
activity: Activity,
userID: String,
roomID: String,
code: String,
mgID: Long,
language: String
) {
iSudFSTAPP?.destroyMG()
iSudFSTAPP = SudMGP.loadMG(activity, userID, roomID, code, mgID, language, mISudFSMMG)
addGameView(iSudFSTAPP!!.gameView)
}
/**
* 3將遊戲view添加到我們的布局當中
*
* @param gameView
*/
private fun addGameView(gameView: View) {
container.removeAllViews()
container.addView(gameView)
}
private fun showToast(content: String?) {
SingleToastUtil.showToast(content)
}
/**
* 通知"文字命中狀態"到遊戲端
*
* @param iSudFSTAPP
* @param keyWord
*/
private fun notifySelfTextHit(keyWord: String?, msg: String) {
LogUtils.d("notifySelfTextHit")
try {
//狀態名稱
val state: String = SudMGPAPPState.APP_COMMON_SELF_TEXT_HIT
//狀態數據
val jsonObject = JSONObject()
jsonObject.put("isHit", true) // true 命中false 未命中
jsonObject.put("keyWord", keyWord) // true 命中false 未命中
jsonObject.put("text", msg) // 聊天原始內容,這裏的值只是一個示例,意指內容當中包含關鍵詞則命中,具體按業務規則定。
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
/**
* 設置當前關鍵詞
*
* @param keyWord
*/
private fun setKeyWord(keyWord: String?) {
mKeyWord = keyWord
}
/**
* 遊戲SDK調用app的接口
*/
private val mISudFSMMG: ISudFSMMG = object : ISudFSMMG {
override fun onGameLog(p0: String?) {
LogUtils.d(p0)
}
override fun onGameLoadingProgress(p0: Int, p1: Int, p2: Int) {
}
override fun onGameStarted() {
}
override fun onGameDestroyed() {
}
/**
* 回調此方法表示令牌過期此時需要刷新令牌並使用ISudFSMStateHandle回調
* @param handle
* @param dataJson
*/
override fun onExpireCode(handle: ISudFSMStateHandle, dataJson: String) {
login(object : AppLoginListener {
override fun onLoginFailure(err: String?) {
}
override fun onLoginSuccess(new_code: String, expire_Date: Long) {
APP_CODE = new_code
try {
val jsonObject = JSONObject()
jsonObject.put("ret_code", 0)
jsonObject.put("ret_msg", "success")
handle.success(jsonObject.toString())
} catch (e: JSONException) {
e.printStackTrace()
}
iSudFSTAPP?.updateCode(APP_CODE, null)
}
})
}
/**
* 處理獲取遊戲視圖信息
* @param handle
* @param dataJson
*/
override fun onGetGameViewInfo(handle: ISudFSMStateHandle, dataJson: String) {
//拿到遊戲View的寬高
val gameViewWidth = container.measuredWidth
val gameViewHeight = container.measuredHeight
if (gameViewWidth > 0 && gameViewHeight > 0) {
notifyGameViewInfo(handle, gameViewWidth, gameViewHeight)
return
}
//如果遊戲View未加載完成則監聽加載完成時回調
container.viewTreeObserver.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
container.viewTreeObserver.removeOnGlobalLayoutListener(this)
val width = container.measuredWidth
val height = container.measuredHeight
notifyGameViewInfo(handle, width, height)
}
})
}
override fun onGetGameCfg(handle: ISudFSMStateHandle?, p1: String?) {
handle?.success(gson.toJson(GameCfg()))
}
/**
* 通知遊戲,遊戲視圖信息
* @param handle
* @param gameViewWidth
* @param gameViewHeight
*/
private fun notifyGameViewInfo(
handle: ISudFSMStateHandle,
gameViewWidth: Int,
gameViewHeight: Int
) {
try {
val jsonObject = JSONObject()
jsonObject.put("ret_code", 0)
jsonObject.put("ret_msg", "success")
//遊戲View大小
val viewSize = JSONObject()
viewSize.put("width", gameViewWidth)
viewSize.put("height", gameViewHeight)
jsonObject.put("view_size", viewSize)
//遊戲安全操作區域
val viewGameRect = JSONObject()
viewGameRect.put("left", 0)
viewGameRect.put("top", ScreenUtil.dip2px(200f))
viewGameRect.put("right", 0)
viewGameRect.put("bottom", ScreenUtil.dip2px(200f))
jsonObject.put("view_game_rect", viewGameRect)
//通知遊戲
val json = jsonObject.toString()
Log.d(TAG, "notifyGameViewInfo:$json")
handle.success(json)
} catch (e: JSONException) {
e.printStackTrace()
}
}
/**
* 遊戲狀態變化
* @param handle
* @param state 狀態名
* @param dataJson 狀態數據json字符串
*/
override fun onGameStateChange(
handle: ISudFSMStateHandle,
state: String,
dataJson: String
) {
Log.d(TAG, "onGameStateChange state:$state--dataJson:$dataJson")
when (state) {
//SudMGPMGState.MG_COMMON_PUBLIC_MESSAGE -> showToast("遊戲:公屏消息")
SudMGPMGState.MG_COMMON_KEY_WORD_TO_HIT -> {
if (TextUtils.isEmpty(dataJson)) {
setKeyWord(null)
} else {
try {
val jsonObject = JSONObject(dataJson)
if (jsonObject.isNull("word")) {
setKeyWord(null)
} else {
val keyWord = jsonObject.getString("word")
setKeyWord(keyWord)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
SudMGPMGState.APP_COMMON_SELF_CLICK_JOIN_BTN -> {
try {
val jsonObject = JSONObject(dataJson)
val seatIndex = jsonObject.optInt("seatIndex", -1)
updateMyMicQueue(GameStatus.STATUS_NOT_READY, true, seatIndex)
} catch (e: Exception) {
e.printStackTrace()
}
}
SudMGPMGState.APP_COMMON_SELF_CLICK_START_BTN -> {
notifySelfPlayingState(true)
}
SudMGPMGState.MG_COMMON_GAME_STATE -> handleGameState(dataJson)
}
}
/**
* 玩家狀態變化
* @param handle
* @param userId 玩家用戶ID
* @param state 狀態名
* @param dataJson 狀態數據json字符串。參考文檔
*/
override fun onPlayerStateChange(
handle: ISudFSMStateHandle,
userId: String,
state: String,
dataJson: String
) {
Log.d(TAG, "onPlayerStateChange userId:$userId--state:$state--dataJson:$dataJson")
when (state) {
SudMGPMGState.MG_COMMON_PLAYER_IN -> handlePlayerIn(userId, dataJson)
SudMGPMGState.MG_COMMON_PLAYER_READY -> handlePlayerReady(userId, dataJson)
SudMGPMGState.MG_COMMON_PLAYER_CAPTAIN -> handlePlayerCaptain(dataJson)
SudMGPMGState.MG_COMMON_PLAYER_PLAYING -> handlePlayerPlaying(userId, dataJson)
}
}
}
private fun handlePlayerIn(userId: String, dataJson: String) {
if (userId != mUid) return
try {
val jsonObject = JSONObject(dataJson)
val retCode = jsonObject.getInt("retCode")
val isIn = jsonObject.getBoolean("isIn")
if (retCode != 0) {
return
}
if (isIn) { // 已加入
if (AvRoomDataManager.get().isRoomOwner) {
notifySelfCaptainState(mUid)
}
} else { // 未加入
var reason = 0
if (jsonObject.has("reason")) {
reason = jsonObject.getInt("reason")
}
if (reason == 0) {
updateMyMicQueue(GameStatus.STATUS_NOT_JOIN)
} else if (reason == 1) {
updateMyMicQueue(GameStatus.STATUS_NOT_JOIN)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun updateMyMicQueue(gameStatus: Int, isJoin: Boolean = false, seatIndex: Int = -1) {
UserModel.get().cacheLoginUserInfo?.gameStatus = gameStatus
val position = AvRoomDataManager.get().getMicPosition(mUid)
if (position != AvRoomDataManager.POSITON_NOT_ON_MIC) {
if (isJoin) notifySelfInState(true, seatIndex)
homePartyModel.updateMyMicQueue(
position,
AvRoomDataManager.get().roomId.toString(),
UserModel.get().cacheLoginUserInfo
).subscribe()
} else if (isJoin) {
val upPosition = AvRoomDataManager.get().findGamePosition()
if (upPosition == Int.MIN_VALUE) {
showToast("當前遊戲人數已滿!")
} else {
UserModel.get().cacheLoginUserInfo?.gameStatus = 1
homePartyModel.upMicroPhone(upPosition,
mUid,
AvRoomDataManager.get().roomId.toString(),
false, object : CallBack<String> {
override fun onSuccess(data: String?) {
notifySelfInState(true, seatIndex)
}
override fun onFail(code: Int, error: String?) {
showToast(error)
}
})
}
}
}
private fun handlePlayerReady(userId: String, dataJson: String) {
if (userId != mUid) return
try {
val jsonObject = JSONObject(dataJson)
val retCode = jsonObject.getInt("retCode")
val isReady = jsonObject.getBoolean("isReady")
if (retCode != 0) {
return
}
updateMyMicQueue(if (isReady) GameStatus.STATUS_READY else GameStatus.STATUS_NOT_READY)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun handlePlayerCaptain(dataJson: String) {
try {
val jsonObject = JSONObject(dataJson)
val retCode = jsonObject.getInt("retCode")
if (retCode != 0) {
return
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun handleGameState(dataJson: String) {
try {
val jsonObject = JSONObject(dataJson)
val gameState = jsonObject.getInt("gameState")
if (gameState == 0) {
onGameStatusChangeListener?.onGameEnd()
} else if (gameState == 2) {
onGameStatusChangeListener?.onGameStart()
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun handlePlayerPlaying(userId: String, dataJson: String) {
if (userId != mUid) return
try {
val jsonObject = JSONObject(dataJson)
val retCode = jsonObject.getInt("retCode")
if (retCode != 0) {
return
}
val isPlaying = jsonObject.getBoolean("isPlaying")
if (isPlaying) {
updateMyMicQueue(GameStatus.STATUS_PLAYING)
} else {
updateMyMicQueue(GameStatus.STATUS_NOT_READY)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun notifySelfInState(isIn: Boolean, seatIndex: Int = -1) {
try {
if (!isIn) {
notifySelfReadyState(false)
}
//狀態名稱
val state = SudMGPAPPState.APP_COMMON_SELF_IN
//狀態數據
val jsonObject = JSONObject()
jsonObject.put("isIn", isIn) // true 加入遊戲false 退出遊戲
if (seatIndex != -1) {
jsonObject.put("seatIndex", seatIndex)
}
jsonObject.put("teamId", 1) //哪一隊伍(2v2,4v4)
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun notifySelfReadyState(isReady: Boolean) {
try {
//狀態名稱
val state = SudMGPAPPState.APP_COMMON_SELF_READY
//狀態數據
val jsonObject = JSONObject()
jsonObject.put("isReady", isReady) // true 準備false 取消準備
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun notifySelfPlayingState(isPlaying: Boolean) {
try {
//狀態名稱
val state = SudMGPAPPState.APP_COMMON_SELF_PLAYING
//狀態數據
val jsonObject = JSONObject()
jsonObject.put("isPlaying", isPlaying) // true 開始遊戲false 結束遊戲
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun notifySelfCaptainState(uid: String) {
try {
//狀態名稱
val state = SudMGPAPPState.APP_COMMON_SELF_CAPTAIN
//狀態數據
val jsonObject = JSONObject()
jsonObject.put("curCaptainUID", uid) // 必填指定隊長uid
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun notifySelfKickState(uid: String) {
try {
//狀態名稱
val state = SudMGPAPPState.APP_COMMON_SELF_KICK
//狀態數據
val jsonObject = JSONObject()
jsonObject.put("kickedUID", uid) // 被踢用戶uid
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun notifySelfEndState() {
try {
//狀態名稱
val state = SudMGPAPPState.APP_COMMON_SELF_END
//狀態數據
val jsonObject = JSONObject()
val dataJson = jsonObject.toString()
//調用接口
iSudFSTAPP?.notifyStateChange(state, dataJson, null)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun onStart() {
iSudFSTAPP?.startMG() //啟動遊戲
}
fun onResume() {
iSudFSTAPP?.playMG() //開始遊戲
}
fun onPause() {
iSudFSTAPP?.pauseMG() //暫停遊戲
}
fun onStop() {
iSudFSTAPP?.stopMG() //停止遊戲
}
fun onDestroy() {
updateMyMicQueue(GameStatus.STATUS_NOT_JOIN)
iSudFSTAPP?.destroyMG()
}
}
internal interface AppLoginListener {
/**
* App Server 登陸失敗, App Server 不能返回CODE
*/
fun onLoginFailure(err: String?)
/**
* App Server 登陸成功, App Server調用服務端接入SDK的API獲取Code 返回給 App
* App 就要用CODE和自己生成的UserID去調用SDK的初始化函數登陸小遊戲
* 小遊戲登陸成功後其UserID就是App傳的UserID
*/
fun onLoginSuccess(new_code: String, expire_Date: Long)
}

View File

@@ -0,0 +1,13 @@
package com.yizhuan.erban.avroom.game
interface OnGameStatusChangeListener {
/**
* 游戏开始
*/
fun onGameStart()
/**
* 游戏结束
*/
fun onGameEnd()
}

View File

@@ -0,0 +1,61 @@
/*
Copyright © Sud.Tech
https://sud.tech
*/
package com.yizhuan.erban.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";
}

View File

@@ -0,0 +1,125 @@
/*
Copyright © Sud.Tech
https://sud.tech
*/
package com.yizhuan.erban.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";
}

View File

@@ -0,0 +1,108 @@
package com.yizhuan.erban.vip
import android.animation.ObjectAnimator
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.widget.FrameLayout
import androidx.core.animation.doOnEnd
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.netease.nimlib.sdk.chatroom.model.ChatRoomMessage
import com.yizhuan.erban.databinding.LayoutVipBroadcastViewBinding
import com.yizhuan.erban.ui.utils.ImageLoadUtils
import com.yizhuan.xchat_android_core.im.custom.bean.VipMessageAttachment
import com.yizhuan.xchat_android_core.room.anotherroompk.ShowUserInfoDialogEvent
import com.yizhuan.xchat_android_core.utils.subAndReplaceDot
import com.yizhuan.xchat_android_core.vip.VipBroadcastMsgEvent
import com.yizhuan.xchat_android_library.rxbus.RxBus
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.concurrent.TimeUnit
class VipBroadcastView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : FrameLayout(context, attrs, defStyleAttr) {
private val binding = LayoutVipBroadcastViewBinding.inflate(LayoutInflater.from(context))
private val messages: MutableList<ChatRoomMessage> by lazy { ArrayList() }
private var disposable: Disposable? = null
init {
addView(binding.root, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT))
binding.llRoot.setOnClickListener {
RxBus.get().post(ShowUserInfoDialogEvent(binding.llRoot.tag as String))
}
EventBus.getDefault().register(this)
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
EventBus.getDefault().unregister(this)
disposable?.dispose()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onVipBroadcastMsgEvent(event: VipBroadcastMsgEvent) {
event.message?.let { addMessage(it) }
}
private fun addMessage(chatRoomMessage: ChatRoomMessage) {
messages.add(chatRoomMessage)
if (isGone) {
isVisible = true
ObjectAnimator.ofFloat(
this,
"alpha",
0f,
1f
)
.setDuration(500)
.start()
}
if (disposable == null || messages.size == 1) {
disposable = Observable.interval(0, 5, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.doOnDispose {
ObjectAnimator.ofFloat(
this,
"alpha",
1f,
0f
)
.setDuration(200)
.apply {
doOnEnd {
binding.tvContent.stop()
isGone = true
}
}
.start()
}
.takeWhile { messages.size > 0 }
.subscribe {
showMessage(messages.removeAt(0))
}
}
}
@SuppressLint("SetTextI18n")
private fun showMessage(chatRoomMessage: ChatRoomMessage?) {
val attachment = chatRoomMessage?.attachment as? VipMessageAttachment ?: return
attachment.vipMessageInfo?.let {
ImageLoadUtils.loadAvatar(it.avatar, binding.ivAvatar)
ImageLoadUtils.loadImage(context, it.vipIcon, binding.ivVipIcon)
binding.tvNick.text = it.nick.subAndReplaceDot(7) + ":"
binding.tvContent.text = it.content
binding.tvContent.start()
binding.llRoot.tag = it.uid.toString()
}
}
}

View File

@@ -0,0 +1,199 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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"
tools:context="com.yizhuan.erban.avroom.fragment.HomePartyRoomFragment">
<data>
<variable
name="click"
type="android.view.View.OnClickListener" />
<variable
name="roomInfo"
type="com.yizhuan.xchat_android_core.room.bean.RoomInfo" />
<variable
name="ktvModel"
type="Boolean" />
<import type="android.view.View" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="@+id/fl_game_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:id="@+id/contribute_list"
android:layout_width="wrap_content"
android:layout_height="22dp"
android:layout_marginTop="80dp"
android:background="@drawable/bg_contribute_entrance"
android:gravity="center_vertical"
android:onClick="@{click}"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_rank_0"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/default_avatar" />
<ImageView
android:id="@+id/iv_rank_1"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/default_avatar" />
<ImageView
android:id="@+id/iv_rank_2"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/default_avatar" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="5dp"
android:text="@string/layout_fragment_game_room_01"
android:textColor="@color/white"
android:textSize="12dp" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginStart="5dp"
android:scaleType="center"
android:src="@drawable/arrow_right_white" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginTop="75dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_show_mini_mic"
android:layout_width="26dp"
android:layout_height="23dp"
android:layout_gravity="end"
android:background="@drawable/bg_mini_mic_entrance"
android:drawableStart="@drawable/ic_room_mic_right"
android:gravity="center"
android:paddingEnd="3dp" />
<LinearLayout
android:id="@+id/ll_mic_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/iv_show_mic"
android:layout_width="12dp"
android:layout_height="22dp"
android:layout_marginStart="5dp"
android:rotation="180"
android:scaleType="centerCrop"
android:src="@drawable/ic_room_mic_right"
android:visibility="gone" />
<com.yizhuan.erban.avroom.widget.MicroView
android:id="@+id/micro_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<com.yizhuan.erban.avroom.widget.BottomView
android:id="@+id/bottom_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
<com.yizhuan.erban.avroom.widget.MessageView
android:id="@+id/message_view"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_above="@id/bottom_view"
android:layout_marginStart="12dp"
android:layout_marginTop="@dimen/dp_5"
android:layout_marginEnd="90dp"
android:layout_marginBottom="@dimen/dp_10" />
<com.yizhuan.erban.ui.widget.rollviewpager.RollPagerView
android:id="@+id/activity_img"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_above="@id/bottom_view"
android:layout_alignParentEnd="true"
android:layout_marginEnd="15dp"
android:layout_marginBottom="8dp"
app:rollviewpager_hint_gravity="center" />
<RelativeLayout
android:id="@+id/input_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
tools:visibility="visible">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="@android:color/white"
android:gravity="center_vertical"
android:orientation="horizontal">
<EditText
android:id="@+id/input_edit"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="@android:color/white"
android:hint="@string/layout_fragment_game_room_02"
android:paddingLeft="10dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:textColor="#888889"
android:textColorHint="#c8c8c8"
android:textSize="12sp" />
<ImageView
android:id="@+id/input_send"
android:layout_width="50dp"
android:layout_height="match_parent"
android:layout_marginLeft="10dp"
android:background="@drawable/click_white_gray_selector"
android:scaleType="center"
android:src="@android:drawable/ic_menu_send" />
</LinearLayout>
</RelativeLayout>
<com.yizhuan.erban.vip.VipBroadcastView
android:id="@+id/vip_broadcast_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="75dp"
android:visibility="gone" />
</RelativeLayout>
</layout>