using System.Collections.Generic; using System.Text; using XWorld.Framework; using XWorld.Framework.Protocol; using RPS.Core; namespace RPS.Server { public sealed class RpsServerRoom : IGameServerRoom { public const ushort SnapshotOpcode = 1; public const ushort ChoiceOpcode = 1; // 客户端出招消息 opcode private readonly RpsLogic _logic = new RpsLogic(); private IRoomCtx _ctx; private RpsState _state; private readonly Dictionary _seatOf = new Dictionary(); // playerId->seat private readonly int[] _pidOfSeat = new int[2]; // seat->playerId(结算用;AI 也有 pid) private bool _ended; public void OnRoomStart(IReadOnlyList players, IRoomCtx ctx) { _ctx = ctx; _state = _logic.CreateInitial(new RoomConfig { GameId = "rps", Version = 1, Seed = 1, PlayerCount = players.Count }, ctx.Random); for (int i = 0; i < players.Count && i < 2; i++) { _seatOf[players[i].PlayerId] = i; _pidOfSeat[i] = players[i].PlayerId; _state.IsAi[i] = players[i].IsAI; } Broadcast(); } public void OnMessage(int playerId, NetMessage message) { if (message.Opcode != ChoiceOpcode) return; if (!_seatOf.TryGetValue(playerId, out int seat)) return; var r = new PacketReader(message.Payload); var choice = (Choice)r.ReadByte(); _state = _logic.Step(_state, RpsInput.Choose(seat, choice), _ctx.Random).State; } public void OnTick(float dt) { if (_ended) return; // Choosing 阶段:AI 座位等概率出招(不读对手),仅在尚未出招时 if (_state.Phase == RpsPhase.Choosing) for (int seat = 0; seat < 2; seat++) if (_state.IsAi[seat] && _state.Choices[seat] == Choice.None) { var c = new[] { Choice.Rock, Choice.Paper, Choice.Scissors }[_ctx.Random.Next(3)]; _state = _logic.Step(_state, RpsInput.Choose(seat, c), _ctx.Random).State; } var res = _logic.Step(_state, RpsInput.Tick(dt), _ctx.Random); _state = res.State; Broadcast(); if (_state.Phase == RpsPhase.Finished) { _ended = true; int s0 = _state.Scores[0], s1 = _state.Scores[1]; bool draw = _state.Winner == 2; _ctx.Logger.Info($"rps finished, winner seat={_state.Winner}, scores {s0}:{s1}"); _ctx.EndRoom(new RoomEndResult { WinnerPlayerId = draw ? 0 : _pidOfSeat[_state.Winner], ResultBlob = Encoding.UTF8.GetBytes(draw ? $"平局 {s0} : {s1}" : $"最终比分 {s0} : {s1}") }); } } public void OnRoomEnd() => _ctx.Logger.Info("rps room end"); private void Broadcast() => _ctx.Broadcast(new NetMessage(SnapshotOpcode, _logic.Encode(_state))); } }