帮派开发

2018/08/21 Mmo-Game

帮派作为大功能模块之一,其中承载了相当多的玩法和养成内容

目录

帮派

一:创建帮派

1.前端发起协议

// 创建帮派
message CSGuildCreate{
    required string name = 1; // 帮派名称
    required string notice = 2; // 帮派宣言
    required int32 label = 3; // 帮派标签
}
/**
* 创建帮派
*
* @param name   帮派名字
* @param notice 帮派宣言
* @param label  标签
*/
public void guildCreate(String name, String notice, int label)
{
    ...
    ...
    玩家等级校验

    帮派名字长度校验

    宣言长度校验

     // 校验屏蔽字,字符串长度,检查并扣除消耗,有问题直接给客户端飘错
    if (ChatUtils.containsName(name))
    {
        // 帮派名字中含有屏蔽字
        sendError(BPErrorCodeEnum.GUILD_NAME_HAVE_SENSITIVE_WORD);
        return;
    }

    if (ChatUtils.containsName(notice))
    {
        // 帮派宣言中含有屏蔽字
        sendError(BPErrorCodeEnum.GUILD_NOTICE_HAVE_SENSITIVE_WORD);
        return;
    }

    if (StringUtils.isPureDigital(name))
    {
        // 帮派名字不能是纯数字
        sendError(BPErrorCodeEnum.GUILD_NAME_NOT_ALL_NUMBER);
        return;
    }

    玩家货币消耗校验

    校验成功发送世界

    ...
    ...
}

分析:校验成功,发送世界创建帮派。 特别注意这里的屏蔽字校验和是否纯数字的方法, 有时间需要单独细看,屏蔽字校验调用的是聊天接口采用的AC过滤算法。

2.世界帮派创建

/**
* 创建帮派
*
* @param actorID 玩家id
* @param name    帮派名字
* @param notice  帮派宣言
* @param label   帮派标签
* @param showParts   外显部件组
*/
public void guildCreate(long actorID, String name, String notice, int label, int[] showParts)
{
    ...
    ...
    从世界缓存里判断当前创建玩家是否已经有帮派

    校验本服帮派数量是否满

    迭代全服所有帮派数据判断帮派名是否重复

    获取帮派序列id

    激活一个新的帮派场景

    构建帮派基本数据到世界内存

    通知帮派场景初始化

    添加帮派建筑数据

    添加初始帮派基金

    计算所有帮派装备总评分

    添加帮派创建事件

    添加到帮派成员列表

    给scene发消息发给创建玩家

    添加到排行榜
}

3.激活一个新的帮派场景

/**
* 激活一个新的帮派场景并返回线id
* @return
*/
public int activeNewGuildSceneline()
{
    return activeSceneline(DictSceneDefineData.guildSceneId);
}
/** 激活新场景 */
public int activeSceneline(int sceneID)
{
    SceneContainer sceneContainer = allSceneMap.get(sceneID);
    if (sceneContainer == null)
    {
        BPLog.BP_SCENE.warn("no sceneID create, id:{}", sceneID);
        return BPErrorCodeEnum.SCENE_NO_SCENE_ID_BE_CREATED;
    }
    return activeNewSceneline(sceneContainer);
}
/**
* 激活一个新的场景线路,激活,并执行
* @param container
* @return 激活的线id
*/
private int activeNewSceneline(SceneContainer container)
{
    //按照顺序,激活一个场景线,取一个SceneUnit就直接return返回了
    SceneUnit sceneUnit = container.activeNewSceneLine();
    if (sceneUnit == null)
    {
        return BPErrorCodeEnum.SCENE_LINE_IS_FULL;
    }

    // 单一派发
    if (container.getSceneStructType() == SceneStructTypeEnum.SINGLE)
    {
        //service派发给processor池执行
        runNewSceneLine(sceneUnit);
    }
}

分析:帮派是同一个场景,如果有新的帮派创建只是激活一个新的线。

4.通知帮派场景初始化

从世界下发消息到场景初始化帮派基本数据
/**
* 帮派场景初始化
*
* @param message 帮派信息
*/
public void guildSceneInit(BPWSGuildSceneInit message)
{
    if (dissolutionState)
    {
        return;
    }

    this.guildId = message.getGuildId();

    this.guildName = message.getGuildName();

    this.lastClearActorTime = 0;

    this.leaderShowData = message.getLeaderShowData();

    this.actorMaxLevel = message.getActorMaxLevel();

}

5.添加帮派建筑数据

// 添加帮派建筑数据,迭代枚举
for (GuildBuildEnum guildBuildEnum : GuildBuildEnum.values())
{
    int buildId = guildBuildEnum.getValue();

    WorldGuildBuildData guildBuildData = new WorldGuildBuildData();
    guildBuildData.setBuildId(buildId);

    // 创建初始,结义堂等级为1级,其他建筑等级为0级
    if (buildId == GuildBuildEnum.JIE_YI_TANG.getValue())
    {
        guildBuildData.setBuildLevel(BPGuildConst.GUILD_INIT_LEVEL);
    }
    else
    {
        guildBuildData.setBuildLevel(0);
    }

    guildData.getBuildDataMap().put(buildId, guildBuildData);
}

分析:迭代建筑枚举类,结义堂等级为1级,其他建筑等级为0级,数据存放在世界线程。

6.推送帮派信息变化时需要特别注意玩家是否在线

/**
* 给玩家发送帮派信息
*
* @param actorId 玩家id
* @param pbGuildData 帮派id
*/
private void guildBaseInfoNotice(long actorId, BPStruct.PBGuildData pbGuildData)
{
    if (!getWorldService().playerIsOnline(actorId))
    {
        return;
    }

    BPWSGuildBaseInfoNotice message = new BPWSGuildBaseInfoNotice(MessageIDConst.WS_GUILD_BASE_INFO_NOTICE, actorId);
    message.setPbGuildData(pbGuildData);
    sendMessageToActor(actorId, message);
}
/**
* 发送消息给指定actor所在的场景
* @param actorID
* @param message
*/
public void sendMessageToActor(long actorID, AbstractServiceMessage message)
{
    BPActorSceneMessage sceneMessage = new BPActorSceneMessage(actorID, message);

    //如果玩家此时不在线了,通过玩家id从world上的场景管理器拿到scene为null,就会报警告
    AbstractBPScene scene = sceneManager.getSceneByActorID(actorID);

    if (scene != null)
    {
        sendMessage(scene, sceneMessage);
    }
    else
    {
        BPLog.BP_SYSTEM.warn("sendMessageToActor:{}, actor not in the scene, msg:{}", actorID, message);
    }
}
从世界线程发送消息到场景玩家,一定要注意判断玩家是否在线,否则会报警告错误。

例如,帮派这种因为帮派建筑物变化就需要通知本帮派所有成员,这就避免不了,有些成员肯定不在线,
所以就要通知在线的成员,在通知的时候需要判断成员是否在线。

类比,时间排行榜奖励称号玩家也有可能不在线的情况。

7.添加帮派创建事件

/**
* 给全帮所有在线玩家推送事件数据到scene上的帮派模块
*
* @param guildData 帮派数据
*/
private void guildEventInfoNoticeToAllMember(WorldGuildData guildData)
{
    ArrayList<WorldGuildEventData> eventList = new ArrayList<>();
    for (int i = 0, size = guildData.getEventDataList().size(); i < size; i++)
    {
        // todo todo 重新new事件对象,防止在scene上误改数据影响world
        eventList.add(guildData.getEventDataList().get(i).clone());
    }

    guildData.setTempToSceneEventList(eventList);

    TLongObjectIterator<WorldGuildMemberData> iterator = guildData.getMemberDataMap().iterator();
    while (iterator.hasNext())
    {
        iterator.advance();

        long toActorId = iterator.value().getActorId();
        if (!getWorldService().playerIsOnline(toActorId))
        {
            continue;
        }

        BPWSGuildEventInfoNotice eventInfoNotice = new BPWSGuildEventInfoNotice(MessageIDConst.WS_GUILD_EVENT_INFO_NOTICE, toActorId);
        eventInfoNotice.setEventList(eventList);
        sendMessageToActor(toActorId, eventInfoNotice);
    }
}

分析:这里一定不要直接把地址从世界传到场景上,防止场景上会根据地址直接影响world上数据。

二:创建帮派

校验是否纯数字

1.采用java正则表达式

引入java.util.regex.Pattern包

public class StringUtils
{
    private static final Pattern PURE_DIGITAL_PATTERN = Pattern.compile("[0-9]*");

    /**
	 * 判断字符串是否是纯数字
	 *
	 * @param value 要检验的字符串
	 * @return true:纯数字 false:否
	 */
	public static boolean isPureDigital(String value)
	{
        return PURE_DIGITAL_PATTERN.matcher(value).matches();
	}
}

Search

    Table of Contents