广告广告
  加入我的最爱 设为首页 风格修改
首页 首尾
 手机版   订阅   地图  繁体 
您是第 3704 个阅读者
 
发表文章 发表投票 回覆文章
  可列印版   加为IE收藏   收藏主题   上一主题 | 下一主题   
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 版主评分版主评分版主评分 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片
推文 x2
[程式] 实现AMXX物件导向编程(OOP)的模块 1.10 版本 (2024/6/28 更新)  (模块 DLL)
原创文章
【插件资讯】

插件来源:原创 https://forums.alliedmods.net...php?t=343808
使用指令:没有
安装路径:gamemod/addons/amxmodx
版本:1.1.0

【插件介绍】

安装需求:

  • 必须使用 AMXX 1.8.3 或以上




下载地址:
https://github.com/hollacs/o...ases/latest



安装方法:
下载后放到 addons/amxmodx
里面有两个测试范例插件, 请自行编译并测试能不能正常运作 (正常应该会在控制台显示正确的输出讯息)



源码: (怕的话可以自行编译)
https://github.com/hollacs...ree/no-std



在许多程式语言中,物件导向编程已经成为一种常见的编程范式。然而,在AMX Mod X (AMXX) 这样的游戏伺服器模块中,物件导向编程并不是很容易实现。为了解决这个问题,我写了一个可以让AMXX实现OOP的模块,使得开发人员可以更方便地使用物件导向编程。

这个模块的核心是一个名为 OO 的库,它提供了一个类别系统,允许开发人员创建自己的类别、物件和方法。OO 库还提供了一些简单的工具,例如存取类别变数和方法的函数。开发人员只需遵循一些简单的规则来声明和使用类别,就可以在AMXX中实现物件导向编程。

为了说明这个模块的使用方法,让我们来看一个简单的例子。

#include <amxmodx>
#include <oo>

#define main plugin_init

public oo_init()
{
  // 定义 Animal 类
  oo_class("Animal")
  {
      new cl[] = "Animal";

      oo_var(cl, "age", 1); // 为 Animal 定义变数 age 表示为这动物的年龄
      oo_var(cl, "name", 32); // 为 Animal 定义变数 name 表示为这动物的名字

      // 定义 Animal 的建构子得到名字和年龄的资料
      oo_ctor(cl, "Ctor", @str{name}, @int{age});

      // 定义 Animal 的解构子
      oo_dtor(cl, "Dtor");

      // 定义 MakeSound 方法 用以回传这动物的声音
      oo_mthd(cl, "MakeSound", @stref{msg}, @int{len});

      // 定义 GetLegs 方法 用以回传这动物有多少条腿
      oo_mthd(cl, "GetLegs");

      // 定义 Introduce 方法 输出这动物的自我介绍
      oo_mthd(cl, "Introduce");

      oo_smthd(cl, "Test"); // 静态方法测试
  }

  // 定义 Dog 类继承自 Animal 类
  oo_class("Dog", "Animal")
  {
      new cl[] = "Dog";

      // 定义建构子, 这会呼叫基类的建构子并输入 Dog 作为名字
      oo_ctor(cl, "Ctor", @int{age});

      // 取代原本的 MakeSound 方法 回传狗的叫声
      oo_mthd(cl, "MakeSound", @stref{msg}, @int{len});

      // 取代原本的 GetLegs 方法 回传狗有多少条腿
      oo_mthd(cl, "GetLegs");
  }

  // 定义 Cat 类继承自 Animal 类
  oo_class("Cat", "Animal")
  {
      new cl[] = "Cat";

      // 定义建构子, 这会呼叫基类的建构子并输入 Cat 作为名字
      oo_ctor(cl, "Ctor", @int{age});

      // 取代原本的 MakeSound 方法 回传猫的叫声
      oo_mthd(cl, "MakeSound", @stref{msg}, @int{len});

      // 取代原本的 GetLegs 方法 回传猫有多少条腿
      oo_mthd(cl, "GetLegs");
  }

  // 同上
  oo_class("Bird", "Animal")
  {
      new cl[] = "Bird";

      oo_ctor(cl, "Ctor", @int{age});

      oo_mthd(cl, "MakeSound", @stref{msg}, @int{len});

      oo_mthd(cl, "GetLegs");
  }

  // 同上
  oo_class("Snake", "Animal")
  {
      new cl[] = "Snake";

      oo_ctor(cl, "Ctor", @int{age});

      oo_mthd(cl, "MakeSound", @stref{msg}, @int{len});

      oo_mthd(cl, "GetLegs");
  }
}

// Animal 的建构子
public Animal@Ctor(const name[], age)
{
  new this = oo_this(); // 获取 this 物件的地址
  oo_set_str(this, "name", name); // 为动物的 name 变数赋以字串的值
  oo_set(this, "age", age); // 为动物的 age 变数赋以整数的值
}

// Animal 的解构子
public Animal@Dtor()
{
  new name[32];
  oo_get_str(oo_this(), "name", name, 32); // 获取这动物的 name 变数的字串值
  server_print("%s 已经被人道毁灭.", name);
}

public Animal@MakeSound(msg[], len)
{
  // format the message to the msg[]
  formatex(msg, len, "我是一个动物");
}

public Animal@GetLegs()
{
  return 0;
}

public Animal@Introduce()
{
  new this = oo_this();

  new name[32];
  oo_get_str(this, "name", name, 32);

  new age = oo_get(this, "age"); // 获取这动物的 age 变数的整数值

  new legs = oo_call(this, "GetLegs"); // 呼叫这动物的 GetLegs 方法, 获取动物的腿数量

  // 呼叫这动物的 MakeSound 方法 and retrieve the result to the msg[]
  new msg[64];
  oo_call(this, "MakeSound", msg, charsmax(msg));

  server_print("你好, 我的名字是 %s, 现在 %d 岁, 有 %d 条腿, 我会说 %s", name, age, legs, msg);
}

public Animal@Test() { server_print("静态方法测试"); }

public Dog@Ctor(age)
{
  // 呼叫父类 Animal 的建构子
  oo_super_ctor("Animal", "Dog", age);
}

public Dog@MakeSound(msg[], len)
{
  formatex(msg, len, "汪汪汪");
}

public Dog@GetLegs()
{
  return 4;
}

public Cat@Ctor(age)
{
  oo_super_ctor("Animal", "Cat", age);
}

public Cat@MakeSound(msg[], len)
{
  formatex(msg, len, "喵喵喵");
}

public Cat@GetLegs()
{
  return 4;
}

public Bird@Ctor(age)
{
  oo_super_ctor("Animal", "Bird", age);
}

public Bird@MakeSound(msg[], len)
{
  formatex(msg, len, "咕咕咕");
}

public Bird@GetLegs()
{
  return 2;
}

public Snake@Ctor(age)
{
  oo_super_ctor("Animal", "Snake", age);
}

public Snake@MakeSound(msg[], len)
{
  formatex(msg, len, "Sss sss");
}

public Snake@GetLegs()
{
  return 0;
}

public main()
{
  register_plugin("[OO] Animal", "0.1", "holla");

  // 建立物件
  new Animal:animals[5];
  animals[0] = oo_new("Dog", 7);
  animals[1] = oo_new("Cat", 6);
  animals[2] = oo_new("Bird", 4);
  animals[3] = oo_new("Snake", 3);
  animals[4] = oo_new("Animal", "Unknown", 0);

  for (new j = 0; j < 5; j++)
  {
      oo_call(animals[j], "Introduce"); // 为每一个物动呼叫自我介绍的方法
  }

     // Tests
     oo_call(0, "Animal@Test"); // Test calling the static method

     server_print("Object #%d %s a Snake", animals[3], oo_isa(animals[3], "Snake") ? "IS" : "IS NOT");
     server_print("Object #%d %s a Dog", animals[3], oo_isa(animals[3], "Dog") ? "IS" : "IS NOT");

     server_print("Class Dog %s a subclass of Animal", oo_subclass_of("Dog", "Animal") ? "IS" : "IS NOT");
     server_print("Class Animal %s a subclass of Cat", oo_subclass_of("Animal", "Cat") ? "IS" : "IS NOT");

     server_print("Class Bird %s", oo_class_exists("Bird") ? "EXISTS" : "DOES NOT EXIST");
     server_print("Class Fish %s", oo_class_exists("Fish") ? "EXISTS" : "DOES NOT EXIST");

     new class[32];
     oo_get_classname(animals[0], class, charsmax(class));
     server_print("Object #%d's classname is %s", animals[0], class);

     server_print("Object #%d %s", animals[0], oo_object_exists(animals[0]) ? "EXISTS" : "DOES NOT EXIST");

     for (new j = 0; j < 5; j++)
     {
           oo_delete(animals[j]); // Delete each animal objects
     }

     server_print("Object #%d %s", animals[0], oo_object_exists(animals[0]) ? "EXISTS" : "DOES NOT EXIST");
}


输出结果
你好, 我的名字叫 Dog, 现在 7 岁, 我有 4 条腿, 我会说 汪汪汪
你好, 我的名字叫 Cat, 现在 6 岁, 我有 4 条腿, 我会说 喵喵喵
你好, 我的名字叫 Bird, 现在 4 岁, 我有 2 条腿, 我会说 咕咕咕
你好, 我的名字叫 Snake, 现在 3 岁, 我有 0 条腿, 我会说 Sss sss
你好, 我的名字叫 Unknown, 现在 0 岁, 我有 0 条腿, 我会说 我是一个动物
静态方法测试
Object #1943714116 IS a Snake
Object #1943714116 IS NOT a Dog
Class Dog IS a subclass of Animal
Class Animal IS NOT a subclass of Cat
Class Bird EXISTS
Class Fish DOES NOT EXIST
Object #461123433's classname is Dog
Object #461123433 EXISTS
Dog 已经被人道毁灭
Cat 已经被人道毁灭
Bird 已经被人道毁灭
Snake 已经被人道毁灭
Unknown 已经被人道毁灭
Object #461123433 DOES NOT EXIST


更多使用方法说明请看 oo.inc


已知问题/限制:

  • 建构子(constructor) 跟 方法(method) 之中不可使用 预设值(default parameter)

  • 类别的变数不支援二维或多维阵列 (2d array)

  • OO_STRING_REF 类型的最大长度为 255 (除非你将字串初始化为大于255个非空字符)




特别感谢 CHATGPT 先生为我打了文章的大部分内容跟范例程式码


[ 此文章被11922911在2024-06-28 17:46重新编辑 ]

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



YouTube: @holla16
献花 x4 回到顶端 [楼 主] From:香港没有资料 | Posted:2023-07-13 18:16 |
cyxnzb 会员卡
个人文章 个人相簿 个人日记 个人地图
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x0 鲜花 x6
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

这个直观来说能实现什么功能呢请问


献花 x0 回到顶端 [1 楼] From:未知地址 | Posted:2023-07-14 17:43 |
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

下面是引用 cyxnzb 于 2023-07-14 17:43 发表的 : 到引言文
这个直观来说能实现什么功能呢请问

这其实不是实现甚么功能的, 这是让编写插件的人能使用OOP的方式来写插件, 让插件开发过程更方便

使用OOP来写东西的好处是能减少重复的程式码, 程式可被高度重复使用, 减少撰写程式错误的风险, 程式更加易于维护 易扩展

详情可以到各大搜寻引擎找找看 "OOP" 或者 "物件导向程式设计", 希望能解答到你的疑问 表情

此文章被评分,最近评分记录
财富:300 (by amore12)


YouTube: @holla16
献花 x1 回到顶端 [2 楼] From:香港没有资料 | Posted:2023-07-14 18:18 |
Nailaz 手机
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖 创作大师奖
小有名气
级别: 小有名气 该用户目前不上站
推文 x77 鲜花 x254
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

酷东西,对程式好有热忱啊!


web front-end and software engineer.
献花 x2 回到顶端 [3 楼] From:台湾中华电信股份有限公司 | Posted:2023-07-17 10:21 |
11922911
个人头像
个人文章 个人相簿 个人日记 个人地图
特殊贡献奖 社区建设奖
初露锋芒
级别: 初露锋芒 该用户目前不上站
推文 x44 鲜花 x96
分享: 转寄此文章 Facebook Plurk Twitter 复制连结到剪贴簿 转换为繁体 转换为简体 载入图片

更新 2023-7-28:
重写内核,使用 AMTL 取代 STL,修正 linux 下崩溃的问题
帖子里加入了新的下载连结


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

此文章被评分,最近评分记录
财富:300 (by amore12) | 理由:


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

更新 版本 1.1.0 (2024-3-15) :
加入多重继承功能 (详见 oo_multiple_inheritance.sma), 多重继承是仿照类似 python 的 MRO order
修正 oo_get 和 oo_set 不能使用类别名称搜索 ex: oo_get(@this, "Class@var")

多重继承范例:
#include <amxmodx>
#include <oo>

public oo_init()
{
     oo_class("B1");
     {
           oo_var("B1", "a", 1);
           oo_ctor("B1", "Ctor", @cell);
           oo_mthd("B1", "Print");
           oo_mthd("B1", "Method1");
     }

     oo_class("B2");
     {
           oo_var("B2", "b", 1);
           oo_ctor("B2", "Ctor", @cell);
           oo_mthd("B2", "Print");
           oo_mthd("B2", "Method2");
     }

     oo_class("D", "B1", "B2");
     {
           oo_var("D", "hp", 1);
           oo_ctor("D", "Ctor", @cell, @cell, @cell);
           oo_mthd("D", "Print");
     }
}

public plugin_init()
{
     new obj = oo_new("D", 100, 689, 777);
     oo_call(obj, "Print");
}

public B1@Ctor(a) { oo_set(oo_this(), "a", a); }

public B2@Ctor(b) { oo_set(oo_this(), "b", b); }

public D@Ctor(hp, a, b)
{
     oo_super_ctor("B1", a);
     oo_super_ctor("B2", b);
     oo_set(@this, "hp", hp);
}

public D@Print()
{
     oo_call(@this, "Method1");
     oo_call(@this, "Method2");

     oo_call(@this, "B1@Print");
     oo_call(@this, "B2@Print");
     server_print("D@Print(hp=%d, a=%d, b=%d)",
           oo_get(@this, "hp"),
           oo_get(@this, "a"),
           oo_get(@this, "b"));
}

public B1@Method1() { server_print("B1@Method1()"); }
public B2@Method2() { server_print("B2@Method2()"); }

public B1@Print() { server_print("B1@Print()"); }
public B2@Print() { server_print("B2@Print()"); }

输出结果
B1@Method1()
B2@Method2()
B1@Print()
B2@Print()
D@Print(hp=100, a=689, b=777)


[ 此文章被11922911在2024-03-17 10:29重新编辑 ]


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

今天在 GitHub 最新的 commit 加入了一个实验性的功能, 但还在测试中
这个功能是 HOOK 挂钩系统, 有了这功能你就可以挂钩所有插件的 OO 方法/建构和解构子

如果你想测试, 你可以到我那个 repo 的 Actions 页面下载最新由 GitHub workflows 自动建置生成好的档案
和下载最新的 oo.inc

档案会在 Action 中的 Artifacts 的区块 (你需要登入 GitHub 才能查看可以下载的档案)



HOOK 挂钩系统 详细使用方法:
(在这个例子中我们将挂钩 oo_animal.sma 中的东西)

复制程式
#include <amxmodx>
#include <oo>

public plugin_init()
{
       // 挂钩 Animal@Ctor() 的建构子
       oo_hook_ctor("Animal", "Ctor", "OnAnimalCtor");

       // 挂钩 Dog@MakeSound() 方法 (post事件)
       oo_hook_mthd("Dog", "MakeSound", "OnDogMakeSound_Post", 1);

       // 挂钩 Snake@GetLegs() 方法
       oo_hook_mthd("Snake", "GetLegs", "OnSnakeGetLegs_1");
       oo_hook_mthd("Snake", "GetLegs", "OnSnakeGetLegs_2");

       // 挂钩 Snake@Test() 方法
       oo_hook_mthd("Snake", "Test", "OnSnakeTest");

       // 挂钩 Animal@Dtor() 的解构子
       oo_hook_dtor("Animal", "OnAnimalDtor");
}

public OnAnimalCtor(const name[], age)
{
       server_print("OnAnimalCtor(name=%s, age=%d)", name, age);
}

public OnDogMakeSound_Post(msg[], len)
{
       server_print("OnDogMakeSound_Post(msg=%s, len=%d)", msg, len);
}

public OnSnakeGetLegs_1()
{
       server_print("OnSnakeGetLegs_1()");
       oo_hook_set_return(369); // 改变这方法原本回传的值
       return OO_CONTINUE;
}

public OnSnakeGetLegs_2()
{
       server_print("OnSnakeGetLegs_2() => oo_hook_get_return()=%d", 
              oo_hook_get_return()); // 获取之前改变了的回传值

       return OO_SUPERCEDE; // 阻止原本这方法的执行
}

public OnSnakeTest(a, &b, const c[], d[], e[5])
{
       server_print("OnSnakeTest(%d, %d, %s, %s, {%d,%d,%d,%d,%d})", a, b, c ,d, e[0], e[1], e[2], e[3], e[4]);

       // 改变第 1 个参数 a 的值做 11
       oo_hook_set_param(1, OO_CELL, 11);

       // 改变第 2 个参数 b 的值做 22 (因为类型是 OO_BYREF 可以直接改)
       b = 22;

       // 改变第 3 个参数 c 的值做 "33"
       oo_hook_set_param(3, OO_STRING, "33");

       // 改变第 4 个参数 d 的值做 "44" (因为类型是 OO_STRING_REF 可以直接改)
       copy(d, 31, "44");

       // 改变第 5 个参数 e 的值做 {11, 22, 33, 44, 55}
       new arr[5] = {11, 22, 33, 44, 55};
       e = arr; // 因为类型是 OO_ARRAY 可以直接改
}

public OnAnimalDtor()
{
       server_print("OnAnimalDtor()");
}


[ 此文章被11922911在2024-06-28 17:46重新编辑 ]


YouTube: @holla16
献花 x0 回到顶端 [6 楼] From:香港没有资料 | Posted:2024-06-28 16:36 |

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