• 欢迎!在发帖前请阅读每个板块置顶的版块须知。论坛 QQ 群:931748551
    鼓励大家多多发帖,这里有问必答。论坛左下角可切换明亮 / 黑暗模式哦。

Part 5.玩家对象

  • 查看 查看: 176
  • 最后更新 最后更新:
  • Part 5.玩家对象​

    本章你将学到:
    • 学习TSPlayer类的字段、方法等
    • 学会Player类的常用字段、方法等

    什么是TSPlayer类?​

    • TSPlayer是TShock的一个类,属于"TShock"的东西。这个类往往包含TShock服务器最常用的玩家数据和方法,其中的方法字段几乎全部对服务端都是有效的。

    什么是Player类?​

    • Player是Terraria的一个类,属于"Terraria"的东西。这个类包含Terraria常用的玩家数据,这个类里的字段、方法繁多且杂乱,而且还包含了许多客户端才有效的字段、方法,只有部分方法、字段服务端可用。

    TSPlayer对象​

    获取TSPlayer对象​

    获取玩家对象的方法有多种,主要根据你的需要选择,下面的代码通过不同的方式获取TSPlayer玩家对象
    • TSPlayer.FindByNameOrID()方法 (主要用于命令)
    TSPlayer.FindByNameOrID()会返回一个列表,包含所有匹配的玩家对象,当然没有匹配结果会返回一个空列表
    C#:
    private void Test(CommandArgs args)
    {
    TSPlayer plr;
    List<TSPlayer> plrs = TSPlayer.FindByNameOrID(args.Parameters[0]);
    //args.Parameters[0]为玩家名字或索引
    //如果参数为 tsi:2 则表示索引为2的玩家
    //如果参数为 tsn:233 则表示名字为233的玩家
    if (plrs.Count == 0)
    {
    args.Player.SendErrorMessage("玩家不存在!"); //发送错误消息
    return;
    }
    else if (plrs.Count > 1)
    {
    args.Player.SendMultipleMatchError(plrs.Select(p => p.Name)); //发送多个匹配结果错误
    //会向玩家发送:
    //找到多个匹配项-无法判断哪个是正确的:
    //玩家1,玩家2....
    //用"半角双引号"包裹关键字来搜索名字带有空格的物品
    //使用 tsi:序号 或者 tsn:名称 来区分含有数字的名称.
    return;
    }
    else
    {
    plr = plrs[0];
    //找到匹配的玩家对象
    }
    }
    • Index索引获取
    C#:
    TSPlayer plr= TShock.Players[index]; //index为玩家索引
    这种方法非常重要,常常用在ServerApi钩子获取TSPlayer对象
    C#:
    //插件加载时执行的代码
    public override void Initialize()
    {
    ServerApi.Hooks.ServerChat.Register(this, OnChat);
    Commands.ChatCommands.Add(new Command(Test, "test"));
    }

    private void OnChat(ServerChatEventArgs args)
    {
    TSPlayer plr = TShock.Players[args.Who]; //获取钩子触发者的TSPlayer对象
    }

    //插件卸载时执行的代码
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    ServerApi.Hooks.ServerChat.Deregister(this, OnChat);
    }
    base.Dispose(disposing);
    }
    • 通过Where进行搜索
    这种方法用于寻找特定条件的玩家,是一种万能的方法,示例代码如下:(p!=null 很重要,请务必写上)
    C#:
    string name = "233"; //假设的量
    string acc = "233";
    string ip = "127.0.0.1";

    TSPlayer plr;
    //var是推断类型的意思,使用var编译器会自己判断变量的类型,下面是一种偷懒的写法,完整的应该是IEnumerable<TSPlayer> plrs
    var plrs= TShock.Players.Where(p => p!=null && p.Name == name); //通过玩家名字获取玩家对象
    //var plrs = TShock.Players.Where(p => p != null && p.Account.Name == acc); //通过账号名字获取玩家对象
    //var plrs = TShock.Players.Where(p => p != null && p.IP == ip); //通过IP获取玩家对象
    //var plrs = TShock.Players.Where(p => p != null && p.Account.Name == acc && p.IP == ip ); //通过IP和账号名字获取玩家对象
    //当然如果你需要的是单个玩家对象,你需要使用下列的代码进行判断
    //如果你需要的符合条件的所有玩家,那么plrs就是结果
    if (plrs.Count() == 0)
    {
    //玩家对象不存在
    return;
    }
    else if (plrs.Count() > 1)
    {
    //玩家对象存在多个
    return;
    }
    else
    {
    plr = plrs.First();
    //plr即为玩家对象
    }

    TSPlayer对象中常用字段和方法​

    • TSPlayer类中的常用属性(加粗的要求记忆,其他的参考就好)
    名称类型作用/含义
    Namestring玩家角色名
    Indexint玩家索引
    GroupGroup玩家所处的组对象
    AccountUserAccount玩家的账号对象
    TPlayerPlayer玩家的Player对象
    UUIDstring玩家客户端的UUID
    IPstring玩家IP地址
    Xfloat玩家的X坐标
    Yfloat玩家的Y坐标
    TileXint玩家所处图格的X坐标(TileX=[取整]X/16)
    TileYint玩家所处图格的Y坐标(TileY=[取整]X/16)
    Teamint玩家队伍(无队伍0,红队1,绿队2,蓝队3,黄队4,粉队5)
    RealPlayerbool正常玩家(true);控制台或REST(false) [主要用于在命令中区分玩家和控制台]
    RespawnTimerint玩家重生计时器(单位:秒)
    LoginAttemptsint玩家登录尝试次数
    Activebool玩家的活动状态(通常为true)
    ConnectionAlivebool玩家的连接状态(正常为true)
    DataWhenJoinedPlayerData玩家加入时的人物数据(即本地存档)
    InventoryIEnumerable<Item>玩家背包(前5行)
    AccessoriesIEnumerable<Item>玩家的配饰
    InventorySlotAvailablebool玩家背包是否有多余
    SelectedItemItem玩家当前手持的物品
    Stateint玩家的客户端状态(与加入服务器有关)
    LastThreatDateTime玩家上次被冻结(Disable)的时间(Utc)
    PaintThresholdint玩家在上一秒漆墙的数量
    ProjectileThresholdint玩家在上一秒生成弹幕的数量
    TileKillThresholdint玩家在上一秒破坏图格的数量
    TileLiquidThresholdint玩家在上一秒放置液体的数量
    TilePlaceThresholdint玩家在上一秒放置图格的数量
    HealOtherThresholdint玩家在上一秒治疗玩家的次数
    TilesCreatedDictionary<Vector2, ITile>玩家放置的待摧毁图格(与图格回弹有关)
    TilesDestroyedDictionary<Vector2, ITile>玩家摧毁的待放置图格(与图格回弹有关)
    AwaitingNamebool等待玩家获取区域名字
    AwaitingNameParameterstring[]获取区域名字时,区域的控制字符(-u 包含保护的区域,-z 包含区域Z索引,-p 玩家将持续接受区域编辑信息?)
    AwaitingTempPointint等待玩家设置区域临时点(0未等待,1点1等待中,2点2等待中)
    • TSPlayer类中的字段(加粗的要求记忆,其他的参考就好)
    字段名类型作用/含义
    AcceptingWhispersbool玩家是否接受耳语(私聊) (/w)
    ActiveChestint玩家当前打开的箱子ID (玩家没有开箱子则未-1)
    AwaitingResponseDictionary<string, Action<object>>玩家等待特定命令的响应的列表(?)
    Confusedbool玩家是否处于控制左右颠倒(已失效)
    Countrystring玩家的国家代码(需要在Config开启EnableGeoIP)(无数据N/A, 代理A1)
    CurrentRegionRegion玩家当前所处的区域
    Deadbool玩家是否处于死亡状态
    Difficultyint玩家的角色难度(软核0,中核1,硬核2,旅行3)
    DisplayLogsbool是否向玩家发送服务器日志
    GodModebool玩家是否已启用上帝模式(直接修改不影响玩家的无敌状态)
    HasBeenNaggedAboutLoggingInbool玩家是否已经被提示过修改区域需要登录
    IceTilesList<Point>玩家放置冰砖(冰杖)的点
    IsDisabledForBannedWearablebool玩家是否由于携带禁用物品而被限制行动(Disable)
    IsDisabledForSSCbool玩家是否由于没有登录以获取SSC数据而被限制行动(Disable)
    IsDisabledForStackDetectionbool玩家是否由于恶意修改物品堆叠而被限制行动(Disable)
    IsDisabledPendingTrashRemovalbool玩家是否由于在登录前在垃圾桶放置物品而被限制行动(Disable)
    IsLoggedInbool玩家是否已经登录
    ItemInHandItem玩家手持的物品
    LastKilledProjectileint玩家上一次试图清除的最后一个弹幕
    LastNetPositionVector2玩家最后更新时的图格坐标(TileXY)
    lastPermissionWarninglong玩家上次被提示无权建筑警告的时间戳
    LastPvPTeamChangeDateTime玩家上次切换队伍或PVP状态的时间
    LastWhisperTSPlayer玩家上次进行耳语(私聊或被私聊)的对象
    LoginHarassedbool玩家是否因为登录而被限制行动(?)
    LoginMSlong玩家加入服务器时的时间戳
    mutebool玩家是否处于禁言状态
    PlayerDataPlayerData玩家的SSC人物数据
    RecentFuseint玩家使用炸药的倒计时,即距离下次可用正常使用炸弹剩余时间(单位: 秒)
    RecentlyCreatedProjectilesList<GetDataHandlers.ProjectileStruct>跟踪这个玩家最近创建的弹幕OnSecondUpdate() 在异步任务中删除这个。超过5秒的投射物将从这个集合中清除,因为它们不再是“最近的”。
    RequestedSectionbool玩家是否已请求过获取地图区块
    RequiresPasswordbool玩家是否被要求输入密码(加入服务器前)
    RPPendingint玩家传送到上次离开服务器位置的倒计时(单位: 秒)
    SilentJoinInProgressbool玩家是否静默加入服务器(不发送玩家加入服务器的提示)
    SilentKickInProgressbool玩家是否静默踢出服务器(不发送玩家踢出服务器的提示)
    sXint玩家出生点的X坐标(修改无效)
    sYint玩家出生点的Y坐标(修改无效)
    TeleportCoordsVector2不明,在TShock已弃用
    tempGroupGroup玩家当前的临时组(会覆盖原来的组)
    tempGroupTimerTimer玩家临时组有效期的计时器
    TempPointsPoint[2]玩家设置的区域临时点
    TPAllowbool玩家是否允许其他玩家对他使用TP类命令(tshock.tp.override忽略此限制)
    • TSPlayer类中的方法(几乎全要记住)
    方法名参数返回值作用
    Banstring reason(封禁理由), string adminUserName = null(管理用户名)bool(封禁是否成功)封禁玩家(通常使用TShock.Bans.InsertBan和Kick组合封禁玩家)
    DamagePlayerint damage(造成伤害点数)void对玩家造成伤害(会造成击退)[如果你只是想扣除玩家血量,请直接修改他的生命值]
    Disablestring reason = ""(理由), DisableFlags flags = DisableFlags.WriteToLog(日志记录模式)void限制玩家行动(石化玩家)
    Disconnectstring reason(理由)void断开玩家连接
    GiveItemint type(物品ID), int stack(物品堆叠), int prefix = 0(物品修饰语ID)void给予玩家物品
    GiveItemCheckint type(物品ID), string name(物品全名[用于检测是否属于封禁物品]), int stack(物品堆叠), int prefix = 0(物品修饰语ID)bool(检查结果)判断玩家是否能被给予某物品
    HasBuildPermissionint x(TileX), int y(TileY), bool shouldWarnPlayer = true(是否警告玩家)bool(检查结果)判断玩家是否能编辑此图格
    HasBuildPermissionForTileObjectint x(TileX), int y(TileY), int width(宽度), int height(高度), bool shouldWarnPlayer = true(是否警告玩家)bool(检查结果)判断玩家是否能编辑以(X,Y)为左下角,宽度为width,高度为height的矩形(只要范围内有一个图格玩家不能编辑就会返回false)
    HasHackedItemStacksbool shouldWarnPlayer = false(是否警告玩家)bool(检查结果)检测玩家是否作弊堆叠(例如:堆叠999999土块)
    HasModifiedIceSuccessfullyint x(TileX), int y(TileY), short tileType(图格类型), GetDataHandlers.EditAction editAction(编辑操作类型)bool(检查结果)判断玩家是否成功编辑冰(冰杖生成的)
    HasPaintPermissionint x(TileX), int y(TileY)bool(检查结果)判断玩家是否能为此图格涂漆
    HasPermissionstring permission(权限)bool(检查结果)判断玩家是否拥有某个权限 (优先级如下: 1.权限钩子修改的结果 2.临时组的权限 3.玩家当前组的权限) [临时组和玩家组的权限不叠加]
    Healint health = 600(治疗点数)void治疗一个玩家
    IsBeingDisabledbool(检查结果)判断玩家是否被限制行动
    IsBouncerThrottledbool(检查结果)判断玩家是否被Bouncer限制(?)
    IsInRangeint x(TileX), int y(TileY), int range = 32(检查半径)bool(检查结果)判断玩家是否在以(X,Y)为圆点range为半径的圆内[当Config的RangeChecks被设为false后无论结果只返回true]
    Kickstring reason(理由), bool force = false(强制踢出[无视tshock.admin.nokick权限]), bool silent = false(不发送广播), string adminUserName = null(管理员名), bool saveSSI = false(保存玩家SSC数据)bool(踢出结果)踢出一名玩家
    KillPlayervoid杀死玩家(对上帝模式玩家无效)[原理是对玩家造成99999点伤害=DamagePlayer(99999)]
    Logoutvoid使玩家登出
    RemoveProjectileint index(弹幕ID), int owner(弹幕发射者索引)void移除一个弹幕(?)
    SaveServerCharacterbool(保存结果)保存玩家的SSC云存档(服务器没有打开SSC时总返回false)
    SetBuffint type(增益ID), int time = 3600(持续帧[1秒=60帧]), bool bypass = false(忽略Bouncer对玩家的限制)void添加玩家BUFF(若玩家已有该BUFF且持续时间更长,你添加的BUFF会被忽略)[BUFF时间不会叠加]
    SetPvPbool mode(true打开,false关闭), bool withMsg = false(是否广播PVP打开提示)void切换玩家PVP状态
    SetTeamint team(无队伍0,红队1,绿队2,蓝队3,黄队4,粉队5)void切换玩家队伍(不发送广播)
    SpawnPlayerSpawnContext context(玩家生成的原因), int? respawnTimer = null(重生倒计时[似乎无效])void复活一个玩家
    Spawnint tilex, int tiley, PlayerSpawnContext context, int? respawnTimer = null, short? numberOfDeathsPVE = null, short? numberOfDeathsPVP = nullvoid复活玩家,大部分参数无效,不做解释
    Teleportfloat x(X坐标), float y(Y坐标), byte style = 1(TP类型[不做解释])void将玩家传送到某一位置
    Whoopieobject time(其实是个int,单位:秒)void发出烦人的声音 需要另开线程使用,否则会卡死主线程
    TempGroupTimerElapsed不做解释不做解释不应该被Pubic的内部方法

    *部分方法例如:SendDate另做介绍
    • 发送消息
    字段名参数返回值作用/含义
    SendMessagestring msg(内容), Color colorvoid发送自定义颜色消息
    SendMessage/SendMessageFromPlayerstring msg(内容), byte red, byte green, byte blue(十进制颜色代码)void发送自定义颜色消息
    SendInfoMessagestring msg(内容), params object[] argsvoid发送黄色提示消息
    SendSuccessMessagestring msg(内容), params object[] argsvoid发送绿色成功消息
    SendWarningMessagestring msg(内容), params object[] argsvoid发送橙色警告消息
    SendErrorMessagestring msg(内容), params object[] argsvoid发送红色错误消息
    SendFileTextAsMessagestring file(文件路径)void将文本文件内容发送给玩家 (支持替换: %map%:地图名 %players%:在线玩家 %specifier%:命令标识符 %onlineplayers%:在线玩家数 %serverslots%:最大玩家数)
    SendMultipleMatchErrorIEnumerable<object> matches(不好解释)void发送多个匹配错误信息
    效果:
    • SendMessage/SendInfoMessage/SendSuccessMessage/SendWarningMessage/SendErrorMessage
    C#:
    args.Player.SendMessage("我是SendMessage~", 255, 155, 15);
    args.Player.SendInfoMessage("我是SendInfoMessage~,你的Index是{0}",args.Player.Index);
    args.Player.SendSuccessMessage("我是SendSuccessMessage~,你现在在{0}地图游玩,所在路径是{1}",Main.worldName,Main.worldPathName);
    args.Player.SendWarningMessage("我是SendWarningMessage~");
    args.Player.SendErrorMessage("我是SendErrorMessage~");
    • SendFileTextAsMessage
    C#:
    args.Player.SendFileTextAsMessage("tshock/motd.txt"); //相对路径
    //args.Player.SendFileTextAsMessage("C:/Users/13110/Desktop/code/TShock144/tshock/motd.txt"); //绝对路径

    代码:
    #motd.txt
    欢迎加入[c/ffff00:%map%]在[c/7ddff8:T][c/81dbf6:S][c/86d7f4:h][c/8ad3f3:o][c/8ecef1:c][c/93caef:k]上运行 [c/55d284:T][c/62d27a:e][c/6fd16f:r][c/7cd165:r][c/89d15a:a][c/95d150:r][c/a4d145:i][c/b1d03b:a]服务器.
    [c/FFFFFF:在线玩家 (%onlineplayers%/%serverslots%):] [c/FFFF00:%players%]
    输入 [c/55D284:%specifier%][c/62D27A:h][c/6FD16F:e][c/7CD165:l][c/89D15A:p] 获取更多帮助信息.
    1704009311526.png
    • SendMultipleMatchError
    C#:
    TSPlayer plr;
    List<TSPlayer> plrs = TSPlayer.FindByNameOrID(args.Parameters[0]);
    //args.Parameters[0]为玩家名字或索引
    //如果参数为 tsi:2 则表示索引为2的玩家
    //如果参数为 tsn:233 则表示名字为233的玩家
    if (plrs.Count == 0)
    {
    args.Player.SendErrorMessage("玩家不存在!"); //发送错误消息
    return;
    }
    else if (plrs.Count > 1)
    {
    args.Player.SendMultipleMatchError(plrs.Select(p => $"{p.Name}({p.Index})")); //发送多个匹配结果错误
    //会向玩家发送:
    //找到多个匹配项-无法判断哪个是正确的:
    //玩家1(0),玩家2(1)....
    //用"半角双引号"包裹关键字来搜索名字带有空格的物品
    //使用 tsi:序号 或者 tsn:名称 来区分含有数字的名称.
    return;
    }
    else
    {
    plr = plrs[0];
    args.Player.SendSuccessMessage("找到匹配项!");
    //找到匹配的玩家对象
    }
    1704009050484.png
    1704009058632.png

    Player对象​

    获取Player对象​

    • 通过TSPlayer获取(推荐)
    C#:
    TSPlayer plr;
    ...(通过上面的方法找到TSPlayer对象)
    Player tplr = plr.TPlayer;
    • 直接通过索引
    C#:
    Player tplr = Main.player[index];
    • 通过Where进行搜索(其实建议先找TSPlayer的...)
      这种方法用于寻找特定条件的玩家,是一种万能的方法,示例代码如下: (p!=null 很重要,请务必写上)
    C#:
    string name = "233"; //假设的量
    Player tplr;

    //var是推断类型的意思,使用var编译器会自己判断变量的类型,下面是一种偷懒的写法,完整的应该是IEnumerable<Player> plrs
    var tplrs = Main.player.Where(p => p != null && p.name == name); //通过玩家名字获取玩家对象
    if (tplrs.Count() == 0)
    {
    //玩家对象不存在
    return;
    }
    else if (tplrs.Count() > 1)
    {
    //玩家对象存在多个
    return;
    }
    else
    {
    tplr = tplrs.First();
    //plr即为玩家对象
    }

    Player对象常用方法和字段​

    • 生命/魔力
    字段名类型作用/意义
    statLifeint玩家当前生命值
    statLifeMaxint玩家生命上限(不包括生命力药水、饰品等额外增加的生命)
    statLifeMax2int玩家生命上限(包括生命力药水、饰品等额外增加的生命)[不可修改]
    statManaint玩家当前魔力值
    statManaMaxint玩家魔力上限(不包括水晶球、饰品等额外增加的魔力)
    statManaMax2int玩家魔力上限(包括水晶球、饰品等额外增加的魔力)[不可修改]
    • 永久增益
    字段名类型作用/意义
    extraAccessorybool恶魔之心(增加饰品格位)
    unlockedBiomeTorchesbool火把神徽章(环境火把)
    ateArtisanBreadbool工匠面包(扩大制作站范围)
    usedAegisCrystalbool生命水晶(永久强化生命再生)
    usedAegisFruitbool埃癸斯果(永久提高防御力)
    usedArcaneCrystalbool奥术水晶(永久提高魔力再生)
    usedGalaxyPearlbool银河珍珠(永久增加运气)
    usedGummyWormbool黏性蠕虫(永久提高钓鱼技能)
    usedAmbrosiabool珍馐(永久提高采矿和建造速度)
    unlockedSuperCartbool矿车升级包
    • 背包库存相关
    字段名类型 (长度)作用/意义
    inventoryItem[] (59)背包(0-49:背包 ; 50-53:钱币 ; 54-58:弹药)
    trashItemItem垃圾桶物品
    bankChest (item:40)猪猪储钱罐(bank.item)
    bank2Chest (item:40)保险箱(bank2.item)
    bank3Chest (item:40)护卫熔炉(bank3.item)
    bank4Chest (item:40)虚空保险箱(bank4.item)
    armorItem[] (20)装备栏 (0:头盔 ; 1:上衣 ; 2裤子 ; 3-9: 配饰) (10:时装头盔 ; 11:时装上衣 ; 12时装裤子 ; 13-19: 时装配饰)
    dyeItem[] (10)染料
    CurrentLoadoutIndexint当前玩家装备栏索引
    LoadoutsEquipmentLoadout(3) (Armor:20;Dye:10)玩家装备栏,eg: Item[] armor = tplr.Loadouts[1].Armor;
    • 群系&环境相关
    字段名类型环境/区域/群系
    ZoneSkyHeightbool太空
    ZoneOverworldHeightbool地表
    ZoneDirtLayerHeightbool地下
    ZoneRockLayerHeightbool洞穴
    ZoneUnderworldHeightbool地狱
    ZoneCorruptbool腐化之地
    ZoneCrimsonbool猩红之地
    ZoneHallowbool神圣之地
    ZoneDesertbool沙漠
    ZoneUndergroundDesertbool地下沙漠
    ZoneJunglebool丛林(雨林)
    ZoneLihzhardTemplebool丛林神庙
    ZoneBeachbool沙滩
    ZoneMarblebool大理石洞
    ZoneShimmerbool微光
    ZoneGraveyardbool墓地
    ZoneDungeonbool地牢
    ZoneMeteorbool陨石群系
    ZoneGlowshroombool发光蘑菇地
    ZoneGranitebool花岗岩洞
    ZoneGemCavebool宝石洞
    ZoneHivebool蜂巢
    ZoneShadowCandlebool暗影蜡烛
    ZonePeaceCandlebool和平蜡烛
    ZoneWaterCandlebool水蜡烛
    ZoneRainbool下雨
    ZoneSnowbool雪地
    ZoneSandstormbool沙尘暴
    ZoneOldOneArmybool撒旦军队
    ZoneTowerNebulabool星云柱
    ZoneTowerSolarbool日耀柱
    ZoneTowerStardustbool星尘柱
    ZoneTowerVortexbool星旋柱
    • 其他
    字段名类型作用/意义
    ghostbool玩家幽灵状态
    luckfloat玩家幸运值
    anglerQuestsFinishedint玩家已完成渔夫任务数
    golferScoreAccumulatedint玩家已经获得的高尔夫球分数
    difficultybyte玩家角色难度(软核0,中核1,硬核2,旅行3)
    SelectedItemint玩家当前手持物品的slot(背包索引)

    习题:​

    1.编写指令/dead,执行后返回当前死亡玩家列表(绿色成功消息)​

    1704012547985.png
    参考答案
    C#:
    using System.Reflection;
    using Terraria;
    using TerrariaApi.Server;
    using TShockAPI;

    namespace Plugin
    {
    [ApiVersion(2, 1)]
    public class Plugin : TerrariaPlugin
    {
    //定义插件的作者名称
    public override string Author => "Cai";
    //插件的一句话描述
    public override string Description => "Player";
    //插件的名称
    public override string Name => "Player";
    //插件的版本
    public override Version Version => Assembly.GetExecutingAssembly().GetName().Version;


    //插件的构造器
    public Plugin(Main game) : base(game)
    {
    }

    //插件加载时执行的代码
    public override void Initialize()
    {
    Commands.ChatCommands.Add(new Command(Dead, "dead"));
    }

    private void Dead(CommandArgs args)
    {
    var plrs = TShock.Players.Where(p => p != null && p.Dead); //通过获取死亡的玩家对象
    if (plrs.Count() == 0)
    {
    //玩家对象不存在
    args.Player.SendSuccessMessage($"当前没有玩家死亡");
    return;
    }
    args.Player.SendSuccessMessage($"当前死亡玩家: {string.Join(',',plrs.Select(p=>p.Name))}");
    }


    //插件卸载时执行的代码
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    var asm = Assembly.GetExecutingAssembly();
    Commands.ChatCommands.RemoveAll(c => c.CommandDelegate.Method?.DeclaringType?.Assembly == asm); //卸载命令
    }
    base.Dispose(disposing);
    }
    }
    }

    2.编写指令"/看看你 {玩家名} ",执行后返回玩家的 生命/生命最大值(魔力无加成最大值)、魔力/魔力最大值(魔力无加成最大值)、玩家的难度(旅行、软、中、硬核)、幸运值luck(绿色成功消息)​

    1704012556825.png
    参考答案
    C#:
    using System.Reflection;
    using Terraria;
    using TerrariaApi.Server;
    using TShockAPI;

    namespace Plugin
    {
    [ApiVersion(2, 1)]
    public class Plugin : TerrariaPlugin
    {
    //定义插件的作者名称
    public override string Author => "Cai";
    //插件的一句话描述
    public override string Description => "Player";
    //插件的名称
    public override string Name => "Player";
    //插件的版本
    public override Version Version => Assembly.GetExecutingAssembly().GetName().Version;

    //插件的构造器
    public Plugin(Main game) : base(game)
    {
    }

    //插件加载时执行的代码
    public override void Initialize()
    {
    Commands.ChatCommands.Add(new Command(See, "看看你"));
    }

    private void See(CommandArgs args)
    {
    TSPlayer plr;
    if (args.Parameters.Count == 0)
    {
    args.Player.SendErrorMessage($"格式错误!正确格式:{TShock.Config.Settings.CommandSpecifier}看看你 玩家名");
    return;
    }
    List<TSPlayer> plrs = TSPlayer.FindByNameOrID(args.Parameters[0]);
    //args.Parameters[0]为玩家名字或索引
    //如果参数为 tsi:2 则表示索引为2的玩家
    //如果参数为 tsn:233 则表示名字为233的玩家
    if (plrs.Count == 0)
    {
    args.Player.SendErrorMessage("玩家不存在!"); //发送错误消息
    return;
    }
    else if (plrs.Count > 1)
    {
    args.Player.SendMultipleMatchError(plrs.Select(p => p.Name)); //发送多个匹配结果错误
    //会向玩家发送:
    //找到多个匹配项-无法判断哪个是正确的:
    //玩家1,玩家2....
    //用"半角双引号"包裹关键字来搜索名字带有空格的物品
    //使用 tsi:序号 或者 tsn:名称 来区分含有数字的名称.
    return;
    }
    else
    {
    plr = plrs[0];
    string difficult = "";
    switch (plr.Difficulty)
    {
    case 3:
    difficult = "旅行";
    break;
    case 0:
    difficult = "软核";
    break;
    case 1:
    difficult = "中核";
    break;
    case 2:
    difficult = "硬核";
    break;
    }
    args.Player.SendSuccessMessage($"{plr.Name}:");
    args.Player.SendSuccessMessage($"生命:{plr.TPlayer.statLife}/{plr.TPlayer.statLifeMax2}({plr.TPlayer.statLifeMax})");
    args.Player.SendSuccessMessage($"魔力:{plr.TPlayer.statMana}/{plr.TPlayer.statManaMax2}({plr.TPlayer.statManaMax})");
    args.Player.SendSuccessMessage($"难度:{difficult}");
    args.Player.SendSuccessMessage($"幸运值:{plr.TPlayer.luck}");
    //找到匹配的玩家对象
    }
    }
    //插件卸载时执行的代码
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    var asm = Assembly.GetExecutingAssembly();
    Commands.ChatCommands.RemoveAll(c => c.CommandDelegate.Method?.DeclaringType?.Assembly == asm); //卸载命令
    }
    base.Dispose(disposing);
    }
    }
    }

    3.编写指令"/看看你的 {玩家名} ",执行后返回玩家猪猪储蓄罐的钱币详情​

    1704013371999.png
    参考答案
    C#:
    using System.Reflection;
    using Terraria;
    using Terraria.ID;
    using TerrariaApi.Server;
    using TShockAPI;

    namespace Plugin
    {
    [ApiVersion(2, 1)]
    public class Plugin : TerrariaPlugin
    {
    //定义插件的作者名称
    public override string Author => "Cai";

    //插件的一句话描述
    public override string Description => "Player";

    //插件的名称
    public override string Name => "Player";

    //插件的版本
    public override Version Version => Assembly.GetExecutingAssembly().GetName().Version;

    //插件的构造器
    public Plugin(Main game) : base(game)
    {
    }

    //插件加载时执行的代码
    public override void Initialize()
    {
    Commands.ChatCommands.Add(new Command(See, "看看你的"));
    }

    private void See(CommandArgs args)
    {
    TSPlayer plr;
    if (args.Parameters.Count == 0)
    {
    args.Player.SendErrorMessage($"格式错误!正确格式:{TShock.Config.Settings.CommandSpecifier}看看你的 玩家名");
    return;
    }
    List<TSPlayer> plrs = TSPlayer.FindByNameOrID(args.Parameters[0]);
    //args.Parameters[0]为玩家名字或索引
    //如果参数为 tsi:2 则表示索引为2的玩家
    //如果参数为 tsn:233 则表示名字为233的玩家
    if (plrs.Count == 0)
    {
    args.Player.SendErrorMessage("玩家不存在!"); //发送错误消息
    return;
    }
    else if (plrs.Count > 1)
    {
    args.Player.SendMultipleMatchError(plrs.Select(p => p.Name)); //发送多个匹配结果错误
    //会向玩家发送:
    //找到多个匹配项-无法判断哪个是正确的:
    //玩家1,玩家2....
    //用"半角双引号"包裹关键字来搜索名字带有空格的物品
    //使用 tsi:序号 或者 tsn:名称 来区分含有数字的名称.
    return;
    }
    else
    {
    plr = plrs[0];
    int copper = 0, silver = 0, gold = 0, platinum = 0;
    foreach (Item item in plr.TPlayer.bank.item)
    {
    switch (item.netID)
    {
    case ItemID.CopperCoin:
    copper += item.stack;
    break;
    case ItemID.SilverCoin:
    silver += item.stack;
    break;
    case ItemID.GoldCoin:
    gold += item.stack;
    break;
    case ItemID.PlatinumCoin:
    platinum += item.stack;
    break;
    }
    }
    args.Player.SendSuccessMessage($"{plr.Name}的小猪储蓄罐硬币情况如下:");
    args.Player.SendSuccessMessage($"[i:{ItemID.PlatinumCoin}]{platinum}");
    args.Player.SendSuccessMessage($"[i:{ItemID.GoldCoin}]{gold}");
    args.Player.SendSuccessMessage($"[i:{ItemID.SilverCoin}]{silver}");
    args.Player.SendSuccessMessage($"[i:{ItemID.CopperCoin}]{copper}");
    }
    }

    //插件卸载时执行的代码
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    var asm = Assembly.GetExecutingAssembly();
    Commands.ChatCommands.RemoveAll(c => c.CommandDelegate.Method?.DeclaringType?.Assembly == asm); //卸载命令
    }
    base.Dispose(disposing);
    }
    }
    }

    4.实现自动队伍,当玩家登录或加入世界,玩家有以下权限就切换对应的队伍​

    权限队伍
    team.red红队(1)
    team.green绿队(2)
    team.blue蓝队(3)
    team.yellow黄队(4)
    team.pink粉队(5)
    钩子: TShockAPI.Hooks.PlayerHooks.PlayerPostLogin、ServerApi.Hooks.NetGreetPlayer
    设置队伍: TSPlayer.SetTeam(int team) (无队伍0,红队1,绿队2,蓝队3,黄队4,粉队5)
    参考答案
    C#:
    using System.Reflection;
    using Terraria;
    using Terraria.ID;
    using TerrariaApi.Server;
    using TShockAPI;
    using TShockAPI.Hooks;


    namespace Plugin
    {
    [ApiVersion(2, 1)]
    public class Plugin : TerrariaPlugin
    {
    //定义插件的作者名称
    public override string Author => "Cai";


    //插件的一句话描述
    public override string Description => "自动队伍";


    //插件的名称
    public override string Name => "AutoTeam";


    //插件的版本
    public override Version Version => Assembly.GetExecutingAssembly().GetName().Version;


    //插件的构造器
    public Plugin(Main game) : base(game)
    {
    }


    //插件加载时执行的代码
    public override void Initialize()
    {
    PlayerHooks.PlayerPostLogin+=OnLogin;
    ServerApi.Hooks.NetGreetPlayer.Register(this,OnGreetPlayers);
    }


    private void OnGreetPlayers(GreetPlayerEventArgs args)
    {
    CheckTeam(TShock.Players[args.Who]);
    }


    private void OnLogin(PlayerPostLoginEventArgs e)
    {
    CheckTeam(e.Player);
    }


    private void CheckTeam(TSPlayer plr)
    {
    if (plr.HasPermission("*"))
    {
    return;
    }
    int team = 0;
    int count = 0;
    if (plr.HasPermission("team.red"))
    {
    team = 1;
    count++;
    }
    if (plr.HasPermission("team.green"))
    {
    team = 2;
    count++;
    }
    if (plr.HasPermission("team.blue"))
    {
    team = 3;
    count++;
    }
    if (plr.HasPermission("team.yellow"))
    {
    team = 4;
    count++;
    }
    if (plr.HasPermission("team.pink"))
    {
    team = 5;
    count++;
    }
    if (count == 0)
    {
    plr.SendWarningMessage("[自动队伍]你所处的玩家组没有配置自动队伍!");
    return;
    }
    if (count > 1)
    {
    plr.SendErrorMessage("[自动队伍]你所处的玩家组配置了多个队伍!");
    return;
    }
    plr.SetTeam(team);
    }


    //插件卸载时执行的代码
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    PlayerHooks.PlayerPostLogin -= OnLogin;
    ServerApi.Hooks.NetGreetPlayer.Deregister(this, OnGreetPlayers);
    }
    base.Dispose(disposing);
    }
    }
    }

    5.当玩家在墓地环境移动时,通过TSPlayer.DamagePlayer()对其造成5点伤害​

    钩子: GetDataHandlers.PlayerUpdate
    参考答案
    C#:
    using System.Reflection;
    using Terraria;
    using Terraria.ID;
    using TerrariaApi.Server;
    using TShockAPI;
    using TShockAPI.Hooks;

    namespace Plugin
    {
    [ApiVersion(2, 1)]
    public class Plugin : TerrariaPlugin
    {
    //定义插件的作者名称
    public override string Author => "Cai";

    //插件的一句话描述
    public override string Description => "墓地";

    //插件的名称
    public override string Name => "ZoneGraveyard";

    //插件的版本
    public override Version Version => Assembly.GetExecutingAssembly().GetName().Version;

    //插件的构造器
    public Plugin(Main game) : base(game)
    {
    }

    //插件加载时执行的代码
    public override void Initialize()
    {
    GetDataHandlers.PlayerUpdate.Register(OnPlayerUpdatePhysics);
    }

    private void OnPlayerUpdatePhysics(object? sender, GetDataHandlers.PlayerUpdateEventArgs e)
    {
    if (e.Player.TPlayer.ZoneGraveyard)
    {
    e.Player.DamagePlayer(5);
    }
    }


    //插件卸载时执行的代码
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    GetDataHandlers.PlayerUpdate.UnRegister(OnPlayerUpdatePhysics);
    }
    base.Dispose(disposing);
    }
    }
    }
  • 正在加载……