Code Monkey home page Code Monkey logo

spmod's Introduction

SPMod License Tux Travis status Windows Appveyor status

SourcePawn Scripting Engine for Half-Life 1 based games

About

SPMod is a Metamod's plugin which is intended to be used as plugin system for Half-Life 1 and its derivatives. It uses SourcePawn as scripting language and allows to change completely the rules of a game or can ease the server administration by adding commands. SPMod's abilities can be extended by writing extensions, known as modules.

Supported games & mods (in future)

  • Half-Life
  • Counter-Strike
  • Counter-Strike: Condition Zero
  • Day of Defeat
  • Team Fortress Classic

For unsupported mods and games, check here.

Example plugin

#include <spmod>

public PluginInfo pluginInfo =
{
	name = "test",
	version = "0.0.0",
	author = "author",
	url = "https://github.com/Amaroq7/SPMod"
};

public void OnPluginInit()
{
    printToServer("Test output\n");
}

Requirements

Building

Linux

Instructions to build SPMod for Linux

Windows

Instructions to build SPMod for Windows

API Reference

API is still in development, it'll be located on project's wiki.

Versioning

We use SemVer for versioning. For the versions available, see the releases.

Contributing

Please read CONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.

License

SPMod is licensed under the General Public License version 3 - see the LICENSE file for details.

Acknowledgments

The SPMod uses code from the following libraries, projects:

spmod's People

Contributors

amaroq7 avatar atuck avatar fantomua avatar garey27 avatar mistrick avatar nuldark avatar wopox1337 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spmod's Issues

SPMod version in plugins

Description

Add info about SPMod version to plugin info struct.
Can help with detection old plugins after breakable changes in API.

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

Player iterators

Description

Create iterators for player loops. Do this for SPMod and for SPMod plugins.

PlayersItterReset();
Player player;
while (PlayersItterNext(PL_ITTER_EXCLUDE_HLTV | PL_ITTER_EXCLUDE_BOTS)) {
  player = PlayersItterGetPlayer();
  // Do some stuf
}

or

for(Player p = GetFirstPlayer(SOME_SEARCH_FLAGS); p; p.NextPlayer(/* flags? */))
{
	// code
}

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

Controlling loading of plugins

Description

The main idea is to control loading procces of plugins. For example this might be useful to enable some plugins at day and other at night. Or some plugins can depend by map name or other factors. But it is so hard to create configuration system that can take all possible options. Thats why i propose to create sm plugin where users can do it manually. Inside this should be only one hook thats can return enable or disable plugin. And of course some natives for getting date/time or map name. For example
forward PluginReturn OnPLuginLoading(PluginInfo pluginInfo);

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

Suggestion: safe precache

Description

Check if file exists before precache, so server wont crash if user forgot to put resource in folder. But we need to stop plugin if resource not precached(SetFailState)

Other Comments

Timer manager

Description

Timer manager should responsible for creating, executing, removing tasks.
Timer would be destroyed after finished execution (one time task) or by using Remove().
Timer with repeat flag could be destroyed returning PluginStop in its callback or by executing Remove().

Example plugin api:

enum TimerFlag
{
    None = 0,
    Repeat = (1<<0)
};

typeset TimerCallback
{
    function PluginReturn (Task task);
    function PluginReturn (Task task, any data);
};

methodmap Task
{
    Task(float time, TimerCallback func, any data = 0, TimerFlag flags = None);
    Remove();
    Trigger();
    Change(float interval, bool trigger = true);
};
  • Operating system: n/a
  • ReHLDS version: n/a
  • Metamod version: n/a
  • SPMod version: master

How do we replicate the issue?

n/a

Expected behavior (i.e. solution)

SPMod should expose api for plugins and modules to manage timers.

Other Comments

n/a

Python-like format syntax

Examples:

Format("Hello, {:s}!", "world"); // "Hello, world"
Format("{0:s}{1:s}{0:s}", "abra", "cad"); // "abracadabra"
Format("The answer is {:d}.", 42); // "42"
Format("Hello, {name:s}! The answer is {number:d}. Goodbye, {name:s}.", FmtArg("name", "World"), FmtArg("number", 42)); // "Hello, World! The answer is 42. Goodbye, World."

There is tagof operator in SP, can we use it for type auto-examination? Can we use it at least for FmtArg? If not, should we add argument in FmtArg to pass the type?

Also we can choose default type for {}, but there are several frequently used types, so I don't prefer it.

Handling of pressing buttons

Description

Create hook for handling of pressing buttons

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

String manager

Description

An awesome methodmap for strings to get rid of char arrays and simplify tones of code. Not sure it all possible, but would be great

Expected behavior (i.e. solution)

String str = "Hello world." // Overloading `=` operator.
str.Format("Foo. %s Bar.", str) // Self formatting,  => `Foo. Hello world. Bar.`
int len = str.Length // `Length` property. => characters count of `Foo. Hello world. Bar.`
str = "Foo. " + str + " Bar." // Overloading `+` operator => `Foo. Hello world. Bar.`
str == "Foo. Hello world. Bar." // Overloading `==` operator => strings equal or not
str.Equals("Foo. Hello world. Bar.", false) // Same as above, but with case sensitivity parameter

Example usage in player class.

String name = player.GetName() // GetName should return String instead of char[]
//Just instead of
new name[33]
player.GetName(name, charsmax(name))

Other Comments

Suggestions?

Project folders

Description

Suggestion:
Create folder scripting for plugins source files, includes and SP compiler
Change current scripts folder to plugins for compiled plugins

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

Consider using clang-format

Description

Code style starts getting a little bit inconsistent across the codebase.

Expected behavior (i.e. solution)

clang-format could unify the code style in SPMod.

Other Comments

n/a

cURL

Could you add curl module support?

Command manager

Description

We should be able to create commands.

There could be natives responsible for creating only console commands (not in say).

typeset CmdCallback
{
    // For client cmd
    function PluginReturn (int client);
    // for srv cmd
    function PluginReturn ();
}
// Client console
RegisterClCmd(const char[] cmd, CmdCallback func, int flags = 0, const char[] info = "")
// Server console
RegisterSrvCmd(const char[] cmd, CmdCallback func, const char[] info = "")

For say we would have forward which is executed on "say" and "say_team" commands.

//1st variant
forward PluginReturn OnSayCommand(int client, bool say_team)
//2nd variant (argv would store first argument of say command, f.e. for "say /test" argv param would store "/test")
forward PluginReturn OnSayCommand(int client, const char[] argv, bool say_team)

Example of registering say command

//1st variant
public PluginReturn OnSayCommand(int client, bool say_team)
{
    char argv[32];
    CmdGetArgv(1, argv, sizeof(argv)); //Not existent native for now
    if (!StrCmp(argv, "/test"))
    {
        SomeCmdCallback(client);
        return PluginStop;
    }
    return PluginContinue;
}

//2nd variant
public PluginReturn OnSayCommand(int client, const char[] argv, bool say_team)
{
    if (!StrCmp(argv, "/test"))
    {
        SomeCmdCallback(client);
        return PluginStop;
    }
    return PluginContinue;
}

Commands permissions

In amxx we have to check permissions manually by executing cmd_access in command callback. I think it would be better to check them in SPMod and execute command callback whenever client has right permissions.

  • Operating system: n/a
  • ReHLDS version: n/a
  • Metamod version: n/a
  • SPMod version: master

How do we replicate the issue?

n/a

Expected behavior (i.e. solution)

We should be able to register commands.

Other Comments

Any thoughts on this?

Handles for mod objects

Description

We need create something similar to this
Uniquie index for all objects instead indexes from 0 to many.

How do we replicate the issue?

Create Handle base class

Expected behavior (i.e. solution)

Other Comments

Message manager

Description

In amxx we have register_message and register_event where event is message_post but have filters(alive, dead, global, etc.)
Maybe we need create something unified?

  • Operating system:
  • ReHLDS version:
  • Metamod version:
  • SPMod version:

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

FileSystem and localization

Description

I think we can fully port FileSystem natives from SourceMod. But it depends by localization, so we need to extend format to support localization(maybe port translations from sourcemod too?)

Expected behavior (i.e. solution)

  • Implement localization
  • Implement natives to work with file system

Cvar manager

Description

Create manager for cvar.
We should know what plugin create a cvar.
Cvar access from plugin should be faster than now, we don't have any cache system.

  • Operating system:
  • ReHLDS version:
  • Metamod version:
  • SPMod version:

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

Issue for projects list

Python-like localization support

Not really python-like, but inspired by it and by #18 of course.

First of all instead of capsing, like DID_DMG_HITS, we can use some default translation text (e.g. english text).
Secondly instead of %L we can use function style: L(player, "He did {damage:d} damage to you with {hits:d} hit(s)\nand still has {health:d}hp and {armor:d}ap.")

This simplifies localization process of plugin that doesn't support it. Look:

Format("He did {damage:d} damage to you with {hits:d} hit(s)\nand still has {health:d}hp and {armor:d}ap."
  , FmtArg("damage", damage)
  , FmtArg("hits", hits)
  , FmtArg("health", player.Health)
  , FmtArg("armor", player.Armor)
);

Becomes:

Format(L(player, "He did {damage:d} damage to you with {hits:d} hit(s)\nand still has {health:d}hp and {armor:d}ap.")
  , FmtArg("damage", damage)
  , FmtArg("hits", hits)
  , FmtArg("health", player.Health)
  , FmtArg("armor", player.Armor)
);

Just adding L(player, and )!

TODO:

  • Plurals
  • SetLanguageContext(player); to remove repetitive player's index in L for localized arguments or using last passed player's index if it isn't passed
  • Translation file auto-creation, on runtime or maybe some source code analyze tool
  • FMTARG macro that will expand FMTARG(var) to FmtArg("var", var)
  • Something that i forgot or don't know about python-like localization

Architecture changes

Description

My suggestion is move binds for other languages to extentions, in core create only interfaces for another modules.
With this we can easier create binds for more languages(if someone will want add support for other language).

Question for discussion:
Maybe better develop metamod instead metaplugin for interfaces?

Players natives

Description

Create get_players analog with own conditions.

// return players in array
native int GetPlayers(int players[32], int flags = 0, ConditionHandler func);

enum PlayerReturn {
    PlayerAllowed,
    PlayerDenied
}

public PlayerReturn PlayerCondition(int player)
{
    if(myFunc(player))
        return PlayerAllowed;
    return PlayerDenied;
}

Create menu with players and own conditions.
Something like native Menu CreatePlayersMenu(MenuHandler handler, int flags, ConditionHandler condition);

How do we replicate the issue?

Expected behavior (i.e. solution)

Other Comments

Convert cvar API to methodmap

Description

Depends on #8.
Natives which access cvar by name could be entirely dropped in favor of pcvars.

Possible api:

enum Cvar
{
    INVALID_CVAR = -1
};

methodmap Cvar
{
    /* this constructor would register cvar */
    public native Cvar(const char[] name, const char[] value, CvarFlags = None);
    public native float GetFloat();
    public native void GetString(char[] value, int size);
    public native int GetInt();
    public native CvarFlags GetFlags();
    public native void SetFloat(float value);
    public native void SetString(const char[] value);
    public native void SetInt(int value);
    public native void SetFlags(CvarFlags flags);
};
native Cvar FindCvar(const char[] name);
  • Operating system: n/a
  • ReHLDS version: n/a
  • Metamod version: n/a
  • SPMod version: n/a

How do we replicate the issue?

n/a

Expected behavior (i.e. solution)

Methodmap API to work with cvar.

Other Comments

n/a

Visual studio project

Meson has built-in VS project generator but its completely fucked up and needs a lot of fixes after generation. Why dont just create project once and add it to repository?

Split include/public

Is your feature request related to a problem? Please describe.
Each module/adapter adds headers to include/public so in the course of time there will be too many headers there. One idea is to separate include/public into each module/adapter.

Additional context
├── public
│ ├── core
│ ├── module 1
│ ├── module 2
│ └── adapter 1

camelCase or CamelCase styling for natives

Description

First natives use camelCase styling, but recently added ones #3 use CamelCase. I think we should decide which one we should go with. Personally I don't mind any of them, but I prefer to keep naming unified.

  • Operating system: n/a
  • ReHLDS version: n/a
  • Metamod version: n/a
  • SPMod version: master

How do we replicate the issue?

n/a

Expected behavior (i.e. solution)

We should go with camelCase or CamelCase styling for natives, not both.

Other Comments

What are your thoughts?

Menu manager

Description

We need API for creating menus.
In amxx exists Old style menu and New menus.
I suggest create all in one.

enum Menu
{
	INVALID_MENU = -1
};

enum MenuStyle
{
	STYLE_ITEMS,
	STYLE_TEXT
}

enum MenuProps
{
	// def 7 like amxx
	MPROP_ITEMS_PER_PAGE,
	// def "\r#num#." like "1. item"
	// custom "\r[#num#]" like "[1] item"
	MPROP_NUMBER_FORMAT,
	// show/hide exit item
	MPROP_EXIT,
	// custom name for exit, back, next
	MPROP_EXIT_NAME,
	MPROP_NEXT_NAME,
	MPROP_BACK_NAME,
	// for hl, etc
	MPROP_NO_COLORS,
};

enum ItemStatus
{
	ITEM_ENABLED,
	ITEM_DISABLED
};


enum MenuItem
{
	MENU_EXIT = -3,
	MENU_NEXT = -2,
	MENU_BACK = -1
};

// typedef MenuHandler = function int (Menu menu, MenuAction action, int param1, int param2);

typeset MenuHandler
{
	// text style
	function void(
		Menu menu,
		int key,
		int player
	);

	// item style
	function void(
		Menu menu,
		MenuItem item,
		int player,
		any data
	);
};

typedef CallbackHandler = function ItemStatus (Menu menu, MenuItem item, int player);


methodmap Menu
{
	// param global if false then destroy after exit
	public native Menu(MenuHandler handler, MenuStyle style = STYLE_ITEMS, bool global = false);
	// param page only for STYLE_ITEMS
	public native void Show(int player, int time = -1, int page = 0);
	
	// only for STYLE_TEXT
	public native void AddText(const char text[]);
	public native void AddKeys(int keys);
	
	// only for STYLE_ITEMS
	public native void SetTitle(const char title[]);
	public native void AddItem(const char name[], any data = 0, CallbackHandler callback = 0);
	// for blank use AddText(0, "\n") or make "\n" by default instead ""
	// TODO: change native name
	public native void AddText(int slot = 0, const char text[] = "");
	public native void SetProp(MenuProps prop, any ...);
	property int Items {
		public native get();
    }
}

// close any active menu
native void CloseMenu(int player);

How do we replicate the issue?

Create manager?

Expected behavior (i.e. solution)

Other Comments

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.