Initial commit: Client Doc docs Server Tools

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ud18010
2026-07-10 10:24:29 +08:00
co-authored by Cursor
commit 7e35d8da31
3374 changed files with 680813 additions and 0 deletions
@@ -0,0 +1,77 @@
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)));
}
}