using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using Newtonsoft.Json; /* 野鸡关卡-联机pk模式 */ public class YejiHuntGameMode_OnlinePK : YejiHuntGameMode, ChallengeGameModeLocalPK { public int currentPlayerIndex = 0; // 双人0和1 float singleShootReadyTime = 30f; float singleShootReadyTimeMax = 30f; public YejiHuntGameMode_OnlinePK(GameMgr gameMgr) : base(gameMgr) { onlineHelper = new OnlineHelper(this); hunterGamePlayerScoreCounter = new HunterGamePlayerScoreCounter(this); } public override void Start() { onlineHelper.InitSocketPlayer(OnStart); } private void OnStart() { banCreateAnimal = onlineHelper.IsCopyHost(); banOnBowArrowShootOut = onlineHelper.IsCopyHost(); Yeji.InitPreHeights(); SetLevel(5); AddHuntGameView(); this.gameMgr.transform.Find("HunterGameView_LocalPK").gameObject.SetActive(true); } public override void onBowShoot() { if (onlineHelper.IsCopyHost()) { onlineHelper.socketPlayer.UploadPKGameData("onBowShoot", ""); } } public override bool DoNextShoot() { if (onlineHelper.IsCopyHost()) { onlineHelper.socketPlayer.UploadPKGameData("DoNextShoot", ""); return false; } foreach (var item in Yeji.yejiSet) { if (item.onlineHandler.onDoNextShootWillDestroy) { GameObject.Destroy(item.gameObject); } } bool canDo = base.DoNextShoot(); if (canDo) { NextPlayerFinal(); } return canDo; } void AddReadyView() { GameObject view = Resources.Load("Prefabs/Views/PKGameReadyView_Challenge"); GameObject o = GameObject.Instantiate(view); PKGameReadyView_Challenge script = o.GetComponent(); script.currentPlayerIndex = currentPlayerIndex; } void NextPlayerFinal() { NextPlayer(); } void NextPlayer() { currentPlayerIndex++; currentPlayerIndex %= 2; singleShootReadyTime = singleShootReadyTimeMax; onlineHelper.roundID++; } public override void Update() { if (!onlineHelper.IsMyPlayerInited()) return; if (!onlineHelper.IsMainHost()) return; if (!onlineHelper.IsMyPlayerRunning()) return; OnUpdate(Time.deltaTime, pauseTimeCounting); } void OnUpdate(float dt, bool _pauseTimeCounting) { if (gameMgr.gameOver || _pauseTimeCounting) return; if (this.time > 0) { this.time -= dt; } else { this.time = 0; AnnounceGameOver(); } if (gameMgr.gameOver || _pauseTimeCounting) return; singleShootReadyTime -= dt; if (singleShootReadyTime <= 0) { //切换玩家 ArmBow.ins.readyShoot(); NextPlayerFinal(); } } public override void FrameUpdate() { onlineHelper.OnFrameUpdate(); } //localPK interface public int GetCurrentPlayIndex() { return currentPlayerIndex; } public (float, float) GetSingleShootReadyTime() { return (singleShootReadyTime, singleShootReadyTimeMax); } HunterGamePlayerScoreCounter hunterGamePlayerScoreCounter; public HunterGamePlayerScoreCounter getHunterGamePlayerScoreCounter() { return hunterGamePlayerScoreCounter; } //###------------ //### 联机部分 //###------------ public class SyncLogicData { public int roundID; public int currentPlayerIndex; public float singleShootReadyTime; public int animalCount = 0; public int arrowCount = 0; public float time = 60; public int[] hitScores; public bool gameEnd = false; public SyncLogicData Input(YejiHuntGameMode_OnlinePK src) { roundID = src.onlineHelper.roundID; currentPlayerIndex = src.currentPlayerIndex; singleShootReadyTime = src.singleShootReadyTime; animalCount = src.animalCount; arrowCount = src.arrowCount; time = src.time; hitScores = src.getHunterGamePlayerScoreCounter().hitScores; gameEnd = src.gameMgr.gameOver; return this; } public void Output(YejiHuntGameMode_OnlinePK dest) { dest.onlineHelper.roundID = roundID; dest.currentPlayerIndex = currentPlayerIndex; dest.singleShootReadyTime = singleShootReadyTime; dest.animalCount = animalCount; dest.arrowCount = arrowCount; dest.time = time; dest.getHunterGamePlayerScoreCounter().hitScores = hitScores; dest.onlineHelper.gameEnd = gameEnd; } } OnlineHelper onlineHelper; public class OnlineHelper { YejiHuntGameMode_OnlinePK gameMode; public OnlineHelper(YejiHuntGameMode_OnlinePK gameMode) { this.gameMode = gameMode; } public SocketPlayer socketPlayer; public int myPlayerIndex = -1; public bool IsMyPlayerInited() { return myPlayerIndex >= 0; } public bool IsMyPlayerRunning() { return myPlayerIndex == gameMode.currentPlayerIndex; } public bool IsMainHost() { return myPlayerIndex == 0; } public bool IsCopyHost() { return myPlayerIndex > 0; } public int roundID = 0; public bool gameEnd = false; public void InitSocketPlayer(Action successCallback) { socketPlayer = SocketPlayer.NewInstance(); socketPlayer.onRoomReadyComplete = () => { myPlayerIndex = GlobalData.playerIndexInRoom; if (successCallback != null) successCallback(); }; socketPlayer.onReceivePKGameData = onReceivePKGameData; AutoSwitchBanUserControlBow(); JCUnityLib.CoroutineStarter.Start(CheckAndUpload()); } bool IsCanUpload() { return GameMgr.ins == gameMode.gameMgr && gameMode.gameMgr; } WaitForSecondsRealtime uploadOnceTime = new WaitForSecondsRealtime(0.033f); IEnumerator CheckAndUpload() { Debug.Log("协程-同步数据-开始"); while (IsCanUpload()) { try { Upload(); } catch (System.Exception e) { Debug.LogError(e.Message); Debug.LogError(e.StackTrace); } yield return uploadOnceTime; } Debug.Log("协程-同步数据-停止"); } Quaternion bowTargetQua; bool hasBowTargBtQua; void onReceivePKGameData(string key, string data) { if (!IsMyPlayerInited()) return; if (key == "logic") { SyncLogicData syncLogicData = JsonConvert.DeserializeObject(data); syncLogicData.Output(this.gameMode); AutoSwitchBanUserControlBow(); } if (key == "bow") { if (!IsMyPlayerRunning()) { string[] quaStr = data.Split(','); if (quaStr.Length == 6) { bowTargetQua.x = float.Parse(quaStr[0]); bowTargetQua.y = float.Parse(quaStr[1]); bowTargetQua.z = float.Parse(quaStr[2]); bowTargetQua.w = float.Parse(quaStr[3]); hasBowTargBtQua = true; ArmBow.ins.phase = int.Parse(quaStr[4]); GameAssistUI.ins.playerScaleAimValue_OnlinePK = int.Parse(quaStr[5]); } } } if (key == "arrow") { List arrowSyncDataList = JsonConvert.DeserializeObject>(data); foreach (var item in arrowSyncMap) { item.Value.hasSetSyncData = false; } GameObject arrowPrefab = ArmBow.ins.arrow; foreach (var item in arrowSyncDataList) { ArrowSync arrowSync; arrowSyncMap.TryGetValue(item.id, out arrowSync); if (arrowSync == null) { GameObject arrowObj = GameObject.Instantiate(arrowPrefab); arrowSync = arrowObj.AddComponent(); arrowSync.SetSyncData(item, true); arrowSyncMap[item.id] = arrowSync; } else { arrowSync.SetSyncData(item); } arrowSync.hasSetSyncData = true; } List removeIDs = null; foreach (var item in arrowSyncMap) { if (!item.Value.hasSetSyncData) { if (removeIDs == null) removeIDs = new List(); removeIDs.Add(item.Key); } } if (removeIDs != null) { foreach (var id in removeIDs) { ArrowSync arrowSync = arrowSyncMap[id]; arrowSyncMap.Remove(id); if (arrowSync && arrowSync.gameObject) { GameObject.Destroy(arrowSync.gameObject); } } } } if (key == "onBowShoot") { GameEventCenter.ins.onBowArrowShootOut?.Invoke(null, null); } if (key == "DoNextShoot") { gameMode.DoNextShoot(); } if (key == "animals") { List syncDataList = JsonConvert.DeserializeObject>(data); foreach (var item in animalSyncMap) { item.Value.onlineHandler.isInvalid = true; } foreach (var item in syncDataList) { Yeji animalSync; animalSyncMap.TryGetValue(item.id, out animalSync); if (animalSync == null) { GameObject animalObject = GameObject.Instantiate(gameMode.animalPrefab, Vector3.zero, Quaternion.identity, gameMode.animalsBaseT); animalSync = animalObject.GetComponent(); animalSync.onlineHandler.isMirror = true; animalSync.onlineHandler.inputSyncData = item; animalObject.SetActive(true); animalSyncMap[item.id] = animalSync; } else { animalSync.onlineHandler.inputSyncData = item; } animalSync.onlineHandler.isInvalid = false; } List removeIDs = null; foreach (var item in animalSyncMap) { if (item.Value.onlineHandler.isInvalid) { if (removeIDs == null) removeIDs = new List(); removeIDs.Add(item.Key); } } if (removeIDs != null) { foreach (var id in removeIDs) { Yeji animalSync = animalSyncMap[id]; animalSyncMap.Remove(id); if (animalSync && animalSync.gameObject) { GameObject.Destroy(animalSync.gameObject); } } } } if (key == "RUpdate") { if (int.Parse(data) == roundID) { gameMode.OnUpdate(uploadOnceTime.waitTime, false); } } if (key == "OnHit") { string[] dataSplits = data.Split(','); int uid = int.Parse(dataSplits[0]); string partName = dataSplits[1]; foreach (var item in Yeji.yejiSet) { if (item.onlineHandler.uid == uid) { item.OnHitLogic(null, partName); break; //一定要break,原因1:这是唯一ID,后续也没必要检测了,原因2:这里可能会触发死亡,死亡会触发下个动物生成,Set集合的元素+1,继续遍历会出现modifyException } } } } public void AutoSwitchBanUserControlBow() { BowCamera.ins.banLogic = ArmBow.ins.banLogic = !IsMyPlayerRunning(); } int lastRoundID = -1; public void OnFrameUpdate() { if (!IsMyPlayerInited()) return; AutoSwitchBanUserControlBow(); if (!IsMyPlayerRunning() && hasBowTargBtQua) { BowCamera.ins.transform.rotation = Quaternion.Lerp(BowCamera.ins.transform.rotation, bowTargetQua, Time.deltaTime * 12); } if (roundID > lastRoundID) { lastRoundID = roundID; gameMode.BanBowReady(); gameMode.AddReadyView(); } if (gameEnd && !gameMode.gameMgr.gameOver) { gameMode.AnnounceGameOver(); } } void Upload() { if (!IsMyPlayerInited()) return; UploadLogic(); UploadBow(); UploadArrows(); UploadAnimals(); UploadRequestUpdate(); UploadOnHit(); } void UploadLogic() { if (!IsMainHost()) return; SyncLogicData data = new SyncLogicData().Input(this.gameMode); socketPlayer.UploadPKGameData("logic", data); } void UploadBow() { if (!IsMyPlayerRunning()) return; Quaternion qua = BowCamera.ins.transform.rotation; int aimScaleValue = GameAssistUI.ins.aimScaleValue; if (!GameAssistUI.ins.scaleAimOn) aimScaleValue = 0; socketPlayer.UploadPKGameData("bow", qua.x + "," + qua.y + "," + qua.z + "," + qua.w + "," + ArmBow.ins.phase + "," + aimScaleValue); } Dictionary arrowSyncMap = new Dictionary(); void UploadArrows() { List arrowSyncDataList = new List(); foreach (var item in Arrow.arrowSet) { if (item.outputSyncData == null || !item.outputSyncData.inited) continue; arrowSyncDataList.Add(item.outputSyncData); } socketPlayer.UploadPKGameData("arrow", arrowSyncDataList); } Dictionary animalSyncMap = new Dictionary(); void UploadAnimals() { if (!IsMainHost()) return; List syncDataList = new List(); foreach (var item in Yeji.yejiSet) { if (item.onlineHandler.outputSyncData == null) continue; syncDataList.Add(item.onlineHandler.outputSyncData); } socketPlayer.UploadPKGameData("animals", syncDataList); } void UploadRequestUpdate() { if (!IsCopyHost()) return; if (!IsMyPlayerRunning()) return; if (gameMode.pauseTimeCounting) return; socketPlayer.UploadPKGameData("RUpdate", this.roundID.ToString()); } void UploadOnHit() { foreach (var item in Yeji.yejiSet) { if (item.onlineHandler.onHitData != null) { socketPlayer.UploadPKGameData("OnHit", item.onlineHandler.onHitData); item.onlineHandler.onHitData = null; } } } } }