广告广告
  加入我的最爱 设为首页 风格修改
首页 首尾
 手机版   订阅   地图  繁体 
您是第 1461 个阅读者
 
发表文章 发表投票 回覆文章
  可列印版   加为IE收藏   收藏主题   上一主题 | 下一主题   
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 版主评分版主评分版主评分 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片
推文 x4
[插件] [OO] 资源管理器 API v0.3 (避免写死档案位置在程式码之中) [2024-6-19 更新]  (model, sound, sprite, generic)
原创文章
【插件资讯】

插件来源:原创
使用指令:无
安装路径:addons/amxmodx

【插件介绍】


安装需求:
* AMXX 1.9.0+
OO 模块

我做了个 API 来避免写死一些档案的位置在程式码之中 (简单来说就是没啥用的东西
有点像 ZP 5.0 的 amx_settings_api.sma
但我把它做得更方便使用并只针对资源档案, 使用了 json 来读取档案位置

先来看个使用范例: (assets_example.sma)
复制程式
#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <oo_assets>

new Assets:g_oAssets;

public plugin_precache()
{
       // 建立物件
       g_oAssets = oo_new("Assets");

       // 为这物件读取 json (以下来说, 读取的位置就是 configs/assets/example.json)
       AssetsLoadJson(g_oAssets, "assets/example.json");
}

public plugin_init()
{
       register_plugin("Assets Exmaple", "0.1", "holla");

       RegisterHam(Ham_Item_Deploy, "weapon_knife", "OnKnifeDeploy_Post", 1);
       RegisterHam(Ham_TraceAttack, "worldspawn", "OnWorldSpawnTraceAttack_Post", 1);

       register_forward(FM_EmitSound, "OnEmitSound");
}

public OnKnifeDeploy_Post(ent)
{
       // 检查有效实体
       if (!pev_valid(ent))
              return;

       // 获取小刀的主人 (玩家id)
       new player = get_ent_data_entity(ent, "CBasePlayerItem", "m_pPlayer");
       if (!player)
              return;

       // 从资源物件中获取 "v_knife" 的模组档位置
       static model[32];
       if (AssetsGetModel(g_oAssets, "v_knife", model, charsmax(model)))
       {
              // 改变玩家的小刀模组
              set_pev(player, pev_viewmodel2, model);
       }
}

public OnWorldSpawnTraceAttack_Post(ent, attacker, Float:damage, Float:direction[3], tr, damagebits)
{
       // 检查有效攻击者
       if (!is_user_alive(attacker))
              return;

       // 攻击者正在使用小刀
       if (get_user_weapon(attacker) == CSW_KNIFE)
       {
              // 从资源物件中获取 "shockwave" 的 spr
              new sprite = AssetsGetSprite(g_oAssets, "shockwave");
              if (sprite)
              {
                     // 获取玩家身处的座标
                     static Float:origin[3];
                     pev(attacker, pev_origin, origin);

                     // 在玩家的位置制造一个冲击波
                     message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin);
                     write_byte(TE_BEAMCYLINDER); // TE id
                     write_coord_f(origin[0]); // x
                     write_coord_f(origin[1]); // y
                     write_coord_f(origin[2]); // z
                     write_coord_f(origin[0]); // x axis
                     write_coord_f(origin[1]); // y axis
                     write_coord_f(origin[2] + 250.0); // z axis
                     write_short(sprite); // sprite
                     write_byte(0); // startframe
                     write_byte(0); // framerate
                     write_byte(10); // life
                     write_byte(30); // width
                     write_byte(0); // noise
                     write_byte(200); // red
                     write_byte(200); // green
                     write_byte(200); // blue
                     write_byte(200); // brightness
                     write_byte(0); // speed
                     message_end();
              }
       }
}

public OnEmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
{
       // 检查生存
       if (!is_user_alive(id))
              return FMRES_IGNORED;
       
       // weapons/
       if (strlen(sample) > 8)
       {
              // 小刀打到墙
              if (equal(sample[8], "knife_hitwall", 13))
              {
                     // 从资源物件在 "knife_hitwall" 中随机获取一个音效 (为何随机? 因为音效可多于一个)
                     static sound[32];
                     if (AssetsGetRandomSound(g_oAssets, "knife_hitwall", sound, charsmax(sound)))
                     {
                            // 取代原本的音效
                            emit_sound(id, channel, sound, volume, attn, flags, pitch);
                            return FMRES_SUPERCEDE;
                     }
              }
              
              // 小刀挥空气
              if (equal(sample[8], "knife_slash", 11))
              {
                     // 从资源物件在 "knife_spk" 中随机获取一个 generic 档 (为何随机? 因为音效可多于一个)
                     static spk[32];
                     if (AssetsGetRandomGeneric(g_oAssets, "knife_spk", spk, charsmax(spk)))
                     {
                            // 播放音效
                            client_cmd(0, "spk %s", spk);

                            // 阻止原本的声音播放
                            return FMRES_SUPERCEDE;
                     }
              }
       }

       return FMRES_IGNORED;
}

JSON档案设定: (configs/assets/example.json)
复制程式
{
    "models": {
        "v_knife" : "models/v_knife_r.mdl"
    },
    "sounds": {
        "knife_hitwall" : ["weapons/hegrenade-1.wav", "weapons/hegrenade-2.wav"]
    },
    "generics" : {
        "knife_spk" : ["sound/hostage/hos1.wav", "sound/hostage/hos2.wav", "sound/hostage/hos3.wav"]
    },
    "sprites" : {
        "shockwave" : "sprites/shockwave.spr"
    }
}


这里注意:
* 每个 model 或 sprite 只能对应一个档案
* 而每个 sound 或 generic 就可以对应多于一个档案
* LoadJson 只能在 plugin_precache() 里面呼叫
* 在一些情况中, 你可能需要将 spr 视为 model, 举个例子你要弄一个 env_sprite 的实体


这个范例插件的作用就是先载入JSON来读取资源档案位置并自动precache预载,
然后小刀打墙会产生一个冲击波(sprite) 和 爆炸音效(sound),
小刀挥空时播放人质音效(generic),
最后, 小刀模组改为CS1.5的样式 (model),
四种资源都示范了一次

INC档一览 (oo_assets.inc)
复制程式
// 获取 SPR 档
stock AssetsGetSprite(any:this, const key[])

// 获取 模组 档
stock AssetsGetModel(any:this, const key[], model[], len)

// 随机获取一个 generic 档 (为何随机? 因为档案可多于一个)
stock bool:AssetsGetRandomGeneric(any:this, const key[], sound[], len)

// 获取 generic 档的动态阵列 handle
stock Array:AssetsGetGeneric(any:this, const key[])

// 随机获取一个 音效 档 (为何随机? 因为档案可多于一个)
stock bool:AssetsGetRandomSound(any:this, const key[], sound[], len)

// 获取 音效 档的动态阵列 handle
stock Array:AssetsGetSound(any:this, const key[])

// 复制物件内容到另一个物件
// other 复制到 this
stock AssetsClone(any:this, any:other)

// 载入 JSON
// @return
// true 为成功, false 是失败
stock bool:AssetsLoadJson(any:this, const filename[])

oo_assets.sma 是核心API 插件

[此文章售价 1 雅币已有 2 人购买]
若发现会员采用欺骗的方法获取财富,请立刻举报,我们会对会员处以2-N倍的罚金,严重者封掉ID!



[ 此文章被11922911在2024-10-13 21:45重新编辑 ]

此文章被评分,最近评分记录
财富:500 (by amore12) | 理由: 辛苦了!!



YouTube: @holla16
献花 x3 回到顶端 [楼 主] From:香港没有资料 | Posted:2024-05-16 05:16 |
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

看到以上的程式码你可能会想, 那不是每一个插件也要弄一个 json? 表情
其实不是, 你可以只在一个插件中读取一次json, 再把那个资源物件的id 分享给其他插件使用

以下是使用 XVar 把物件 id 分享给其他插件的方法

需要载入 json 的插件这样写:
复制程式
#include <amxmodx>
#include <oo_assets>

public Assets:AssetsObject;

public plugin_precache()
{
       AssetsObject = oo_new("Assets");
       AssetsLoadJson(AssetsObject, "assets/test.json");
}

用于简化程序的一个stock function (可写在你的自定义inc中)
复制程式
stock any:GetXVarObject(const name[])
{
       new xvar = get_xvar_id(name);
       if (xvar == -1)
              set_fail_state("XVar does not exist: %s", name);
       
       new any:object = get_xvar_num(xvar);
       if (!oo_object_exists(object))
              set_fail_state("Object does not exist: %d", object);

       return object;
}

这是其他插件A:
复制程式
new Assets:g_oAssets;

public plugin_init()
{
       g_oAssets = GetXVarObject("AssetsObject");
       register_clcmd("test_mp3", "CmdTestMp3");
}

public CmdTestMp3(id)
{
       static music[64];
       if (AssetsGetRandomGeneric(g_oAssets, "music", music, charsmax(music)))
              client_cmd(id, "mp3 play %s", music);
       
       return PLUGIN_HANDLED;
}

这是其他插件B:
复制程式
new Assets:g_oAssets;

public plugin_init()
{
       g_oAssets = GetXVarObject("AssetsObject");
       register_clcmd("test_spk", "CmdTestSpk");
}

public CmdTestSpk(id)
{
       static spk[64];
       if (AssetsGetRandomGeneric(g_oAssets, "spk", spk, charsmax(spk)))
              client_cmd(id, "spk %s", spk);
       
       return PLUGIN_HANDLED;
}

JSON档案设定 (这只是个范例)
复制程式
{
       "generics" : {
              "music" : "sound/test/resident_evil.mp3",
              "spk" : "sound/test/door_stuck.wav"
       }
}

XVar 的详细使用方法可以看看 a78 大的教学


[ 此文章被11922911在2024-06-19 15:03重新编辑 ]

此文章被评分,最近评分记录
威望:5 (by amore12) | 理由: 辛苦了!!


YouTube: @holla16
献花 x2 回到顶端 [1 楼] From:香港没有资料 | Posted:2024-05-16 05:25 |
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

如果担心效能问题其实可以有一些应对方案
譬如在 plugin_init() 一开始就预先用一个变数来获取某个档案, 以后就用那个变数来设定 (只针对 model 或 sprite)
复制程式
new g_KnifeModel[64];
new g_ShockwaveSpr;
...
public plugin_init()
{
       ...
       AssetsGetModel(g_oAssets, "v_knife", g_KnifeModel, charsmax(g_KnifeModel));
       g_ShockwaveSpr = AssetsGetSprite(g_oAssets, "shockwave");
}

public OnKnifeDeploy_Post(ent)
{
       ...
       if (g_KnifeModel[0])
              set_pev(player, pev_viewmodel2, g_KnifeModel);
}

public OnWorldSpawnTraceAttack_Post(ent, attacker, Float:damage, Float:direction[3], tr, damagebits)
{
       ...
       if (g_ShockwaveSpr)
       {
              message_begin_f(MSG_PVS, SVC_TEMPENTITY, origin);
              write_byte(TE_BEAMCYLINDER); // TE id
              ...
              write_short(g_ShockwaveSpr);
              message_end();
       }
}

而 sound 及 generic 则可以预先获取 Array 的 handle
复制程式
new Array:g_aHitWallSound;
new Array:g_aSlashSound;
...
public plugin_init()
{
       ...
       g_aHitWallSound = AssetsGetSound(g_oAssets, "knife_hitwall");
       g_aSlashSound = AssetsGetGeneric(g_oAssets, "knife_spk");
}

复制程式
public OnEmitSound(id, channel, const sample[], Float:volume, Float:attn, flags, pitch)
{
       ...
       if (equal(sample[8], "knife_hitwall", 13))
       {
              if (g_aHitWallSound != Invalid_Array)
              {
                     static sound[64];
                     ArrayGetRandomString(g_aHitWallSound, sound, charsmax(sound));
                     emit_sound(id, channel, sound, volume, attn, flags, pitch);
                     return FMRES_SUPERCEDE;
              }
       }
       if (equal(sample[8], "knife_slash", 11))
       {
              if (g_aSlashSound != Invalid_Array)
              {
                     static sound[64];
                     ArrayGetRandomString(g_aSlashSound, sound, charsmax(sound));
                     client_cmd(0, "spk %s", sound);
                     return FMRES_SUPERCEDE;
              }
       }
}

复制程式
stock ArrayGetRandomString(Array:handle, sound[], maxlen)
{
       ArrayGetString(handle, random(ArraySize(handle)), sound, maxlen);
}


[ 此文章被11922911在2024-05-16 18:55重新编辑 ]

此文章被评分,最近评分记录
支持度:100 (by amore12) | 理由: 辛苦了!!


YouTube: @holla16
献花 x2 回到顶端 [2 楼] From:香港没有资料 | Posted:2024-05-16 13:23 |
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

更新版本 v0.2 (2024-5-30):
- 在 inc 加入了安全检查, 检查 this 物件是否为有效
- 在 Assets@GetSprite() 找不到指定 spr 时将原本 return -1 改为 return 0


[ 此文章被11922911在2024-06-19 13:40重新编辑 ]


YouTube: @holla16
献花 x0 回到顶端 [3 楼] From:香港没有资料 | Posted:2024-05-30 11:57 |
h84293451
数位造型
个人文章 个人相簿 个人日记 个人地图
路人甲
级别: 帐号封锁 该用户目前不上站
推文 x0 鲜花 x0
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

回 覆 锁 定 :

  此回覆已被锁定,只有『管理员及回覆者』看的到 !!!




献花 x0 回到顶端 [4 楼] From:台湾宽频通讯顾问股份有限公司 | Posted:2024-06-09 01:55 |
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

更新版本 v0.3 (2024-6-19):
- 减少重复的代码
- Assets@LoadJson 使用 log_amx() 取代原本的 abort()
- 加入档案不存在的 log 讯息
- 加入 AssetsLoadJson() (比直接用 oo_call 更安全的方法)
- 加入 AssetsClone() 复制物件功能 (用法详见下面)

附件已更新




在 0.3 版本你可以复制一个 Assets 物件的内容到另一个物件之中 (比重新载入一次相同的JSON速度更快)

用法:
复制程式
#include <amxmodx>
#include <oo_assets>

new Assets:g_Object1, Assets:g_Object2;

public plugin_precache()
{
       g_Object1 = oo_new("Assets"); // 建立物件1
       AssetsLoadJson(g_Object1, "assets/exmaple.json"); // 载入JSON

       g_Object2 = oo_new("Assets"); // 建立物件2
       AssetsClone(g_Object2, g_Object1); // 将 物件1 的内容复制到 物件2
}


[ 此文章被11922911在2024-06-19 15:04重新编辑 ]


YouTube: @holla16
献花 x0 回到顶端 [5 楼] From:香港没有资料 | Posted:2024-06-19 13:49 |

首页  发表文章 发表投票 回覆文章
Powered by PHPWind v1.3.6
Copyright © 2003-04 PHPWind
Processed in 0.099151 second(s),query:16 Gzip disabled
本站由 瀛睿律师事务所 担任常年法律顾问 | 免责声明 | 本网站已依台湾网站内容分级规定处理 | 连络我们 | 访客留言