Files
2026-07-10 10:24:29 +08:00

78 lines
3.1 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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<int, int> _seatOf = new Dictionary<int, int>(); // playerId->seat
private readonly int[] _pidOfSeat = new int[2]; // seat->playerId(结算用;AI 也有 pid
private bool _ended;
public void OnRoomStart(IReadOnlyList<PlayerInfo> 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)));
}
}