FunGame-Core/Library/Common/Addon/Example/ExampleGameModule.cs
milimoe c51b7c50fa
统一命名 并禁止GameModuleServer调用DataRequest (#81)
* 统一命名 并禁止GameModuleServer调用DataRequest

* 添加了GameModuleDepend (依赖集合) 用于整合Maps Characters Items Skills
2024-08-01 20:40:25 +08:00

212 lines
7.8 KiB
C#
Raw 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;
using Milimoe.FunGame.Core.Api.Utility;
using Milimoe.FunGame.Core.Entity;
using Milimoe.FunGame.Core.Interface;
using Milimoe.FunGame.Core.Interface.Base;
using Milimoe.FunGame.Core.Library.Common.Event;
using Milimoe.FunGame.Core.Library.Constant;
using Milimoe.FunGame.Core.Model;
// 此演示包含GameModule、GameModuleServer、GameMap
namespace Milimoe.FunGame.Core.Library.Common.Addon.Example
{
/// <summary>
/// 建议使用一个类来存储常量,方便重用
/// </summary>
public class ExampleGameModuleConstant
{
public static GameModuleDepend GameModuleDepend => _depends;
private static readonly string[] Maps = ["Example GameMap"];
private static readonly string[] Characters = [];
private static readonly string[] Items = [];
private static readonly string[] Skills = [];
private static readonly GameModuleDepend _depends = new(Maps, Characters, Items, Skills);
}
/// <summary>
/// 模组:必须继承基类:<see cref="GameModule"/><para/>
/// 继承事件接口并实现其方法来使模组生效。例如继承:<seealso cref="IGamingConnectEvent"/><para/>
/// </summary>
public class ExampleGameModule : GameModule, IGamingConnectEvent
{
public override string Name => "FunGame Example GameModule";
public override string Description => "My First GameModule";
public override string Version => "1.0.0";
public override string Author => "FunGamer";
public override string DefaultMap => GameModuleDepend.Maps.Length > 0 ? GameModuleDepend.Maps[0] : "";
public override GameModuleDepend GameModuleDepend => ExampleGameModuleConstant.GameModuleDepend;
public override RoomType RoomType => RoomType.Mix;
protected Gaming? Instance;
protected Room room = General.HallInstance;
protected List<User> users = [];
protected Dictionary<string, Character> characters = [];
public override void StartGame(Gaming instance, params object[] args)
{
Instance = instance;
// 取得房间玩家等信息
GamingEventArgs eventArgs = instance.EventArgs;
room = eventArgs.Room;
users = eventArgs.Users;
characters = eventArgs.Characters;
// 客户端做好准备后,等待服务器的消息通知,下面可以根据需求进一步处理
}
public override void StartUI(params object[] args)
{
// 如果你是一个WPF或者Winform项目可以在这里启动你的界面
// 如果没有,则不需要重写此方法
}
public void BeforeGamingConnectEvent(object sender, GamingEventArgs e, Hashtable data, Hashtable result)
{
// 此方法预处理攻击消息
// 如果这里将Cancel设置为true那么这个方法结束后后续的事件就会终止
e.Cancel = true;
}
public void AfterGamingConnectEvent(object sender, GamingEventArgs e, Hashtable data, Hashtable result)
{
}
public void SucceedGamingConnectEvent(object sender, GamingEventArgs e, Hashtable data, Hashtable result)
{
}
public void FailedGamingConnectEvent(object sender, GamingEventArgs e, Hashtable data, Hashtable result)
{
_ = DiscountGameModuleServer();
}
public async Task DiscountGameModuleServer()
{
// 这是一个主动请求服务器的示例:
Api.Transmittal.DataRequest request = Controller.NewDataRequest(DataRequestType.Gaming);
request.AddRequestData("type", GamingType.Disconnect);
if (await request.SendRequestAsync() == RequestResult.Success)
{
string msg = request.GetResult<string>("msg") ?? string.Empty;
Controller.WriteLine(msg);
}
}
}
/// <summary>
/// 模组服务器:必须继承基类:<see cref="GameModuleServer"/><para/>
/// 使用switch块分类处理 <see cref="GamingType"/>。
/// </summary>
public class ExampleGameModuleServer : GameModuleServer
{
public override string Name => "FunGame Example GameModule";
public override string Description => "My First GameModule";
public override string Version => "1.0.0";
public override string Author => "FunGamer";
public override string DefaultMap => GameModuleDepend.Maps.Length > 0 ? GameModuleDepend.Maps.First() : "";
public override GameModuleDepend GameModuleDepend => ExampleGameModuleConstant.GameModuleDepend;
protected Room Room = General.HallInstance;
protected List<User> Users = [];
protected IServerModel? RoomMaster;
protected Dictionary<string, IServerModel> Others = [];
protected Dictionary<string, IServerModel> All = [];
public override bool StartServer(string GameModule, Room Room, List<User> Users, IServerModel RoomMasterServerModel, Dictionary<string, IServerModel> OthersServerModel, params object[] Args)
{
// 将参数转为本地属性
this.Room = Room;
this.Users = Users;
RoomMaster = RoomMasterServerModel;
Others = OthersServerModel;
if (RoomMaster != null)
{
// 这里获得了每名玩家的服务线程,保存为一个字典
All = OthersServerModel.ToDictionary(k => k.Key, v => v.Value);
All.Add(RoomMaster.User.Username, RoomMaster);
}
// 创建一个线程执行Test()
TaskUtility.NewTask(Test).OnError(Controller.Error);
return true;
}
private readonly List<User> ConnectedUser = [];
private async Task Test()
{
// 通常,我们可以对客户端的连接状态进行确认,此方法展示如何确认客户端的连接
Controller.WriteLine("欢迎各位玩家进入房间 " + Room.Roomid + " 。");
SendAll(SocketMessageType.Gaming, GamingType.Connect);
// 新建一个线程等待所有玩家确认
while (true)
{
if (ConnectedUser.Count == Users.Count) break;
// 每200ms确认一次不需要太频繁
await Task.Delay(200);
}
Controller.WriteLine("所有玩家都已经连接。");
}
public override Hashtable GamingMessageHandler(string username, GamingType type, Hashtable data)
{
Hashtable result = [];
switch (type)
{
case GamingType.Connect:
// 编写处理“连接”命令的逻辑
ConnectedUser.Add(Users.Where(u => u.Username == username).First());
Controller.WriteLine(username + "已经连接。");
break;
}
return result;
}
private void SendAll(SocketMessageType type, params object[] args)
{
// 循环服务线程,向所有玩家发送消息
foreach (IServerModel s in All.Values)
{
if (s != null && s.Socket != null)
{
s.Send(s.Socket, type, args);
}
}
}
}
/// <summary>
/// 地图:必须继承基类:<see cref="GameMap"/><para/>
/// </summary>
public class ExampleGameMap : GameMap
{
public override string Name => "Example GameMap";
public override string Description => "My First GameMap";
public override string Version => "1.0.0";
public override string Author => "FunGamer";
public override float Width => 12.0f;
public override float Height => 12.0f;
public override float Size => 4.0f;
}
}