Add networked Fighter3D minigame
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Fighter3D.Core;
|
||||
using XWorld.Framework;
|
||||
using XWorld.Framework.Protocol;
|
||||
|
||||
namespace Fighter3D.Server
|
||||
{
|
||||
public sealed class FighterServerRoom : IGameServerRoom
|
||||
{
|
||||
public const ushort InputOpcode = 1;
|
||||
public const ushort SnapshotOpcode = 100;
|
||||
|
||||
private readonly FighterLogic _logic = new FighterLogic();
|
||||
private readonly Dictionary<int, int> _seatOfPlayer = new Dictionary<int, int>();
|
||||
private readonly int[] _playerOfSeat = new int[2];
|
||||
private IRoomCtx _ctx;
|
||||
private FighterState _state;
|
||||
private bool _ended;
|
||||
|
||||
public void OnRoomStart(IReadOnlyList<PlayerInfo> players, IRoomCtx ctx)
|
||||
{
|
||||
_ctx = ctx;
|
||||
_state = _logic.CreateInitial(
|
||||
new RoomConfig { GameId = "fighter3d", Version = 1, Seed = 1, PlayerCount = players.Count },
|
||||
ctx.Random);
|
||||
|
||||
for (int i = 0; i < players.Count && i < 2; i++)
|
||||
{
|
||||
_seatOfPlayer[players[i].PlayerId] = i;
|
||||
_playerOfSeat[i] = players[i].PlayerId;
|
||||
}
|
||||
|
||||
Broadcast();
|
||||
}
|
||||
|
||||
public void OnMessage(int playerId, NetMessage message)
|
||||
{
|
||||
if (_ended || message.Opcode != InputOpcode)
|
||||
return;
|
||||
|
||||
if (!_seatOfPlayer.TryGetValue(playerId, out int seat))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var reader = new PacketReader(message.Payload);
|
||||
int axis = reader.ReadVarInt();
|
||||
var buttons = (FighterButtons)reader.ReadByte();
|
||||
_state = _logic.Step(_state, FighterInput.Controls(seat, axis, buttons), _ctx.Random).State;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_ctx.Logger.Error($"fighter3d input decode failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTick(float deltaTime)
|
||||
{
|
||||
if (_ended)
|
||||
return;
|
||||
|
||||
var result = _logic.Step(_state, FighterInput.Tick(deltaTime), _ctx.Random);
|
||||
_state = result.State;
|
||||
Broadcast();
|
||||
|
||||
if (_state.Phase == FighterPhase.Finished)
|
||||
EndRoomOnce();
|
||||
}
|
||||
|
||||
public void OnRoomEnd()
|
||||
{
|
||||
_ctx?.Logger.Info("fighter3d room end");
|
||||
}
|
||||
|
||||
private void Broadcast()
|
||||
{
|
||||
_ctx.Broadcast(new NetMessage(SnapshotOpcode, _logic.Encode(_state)));
|
||||
}
|
||||
|
||||
private void EndRoomOnce()
|
||||
{
|
||||
if (_ended)
|
||||
return;
|
||||
|
||||
_ended = true;
|
||||
int winnerPid = _state.WinnerSeat >= 0 && _state.WinnerSeat < 2
|
||||
? _playerOfSeat[_state.WinnerSeat]
|
||||
: 0;
|
||||
|
||||
string text = _state.WinnerSeat == 2
|
||||
? "Fighter3D draw"
|
||||
: $"Fighter3D winner seat {_state.WinnerSeat}";
|
||||
|
||||
_ctx.EndRoom(new RoomEndResult
|
||||
{
|
||||
WinnerPlayerId = winnerPid,
|
||||
ResultBlob = Encoding.UTF8.GetBytes(text)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user