A simple but extensible economy engine for PocketMine-MP, using label-oriented APIs.

Overview

Capital

A simple but very extensible economy plugin for PocketMine-MP.

How is Capital different from other economy plugins?

Capital introduces a label-oriented paradigm, allowing Capital to be extensible for many purposes:

  • Currencies are no longer imposed by the core. You don't need to deal with currencies if you don't want to, and you can create as many currencies as you like without breaking things.
  • The planned Wallet extension allows connecting inventory items to player accounts, and this is automatically compatible with other plugins that are not even aware of wallets.
  • Analytics can be easily achieved using label-based queries. Track how capital flows in your server without writing code!

Labels

Capital uses labels to identify accounts. In a nutshell, every account has:

  • a UUID (which has nothing to do with the player UUID)
  • a balance value (signed 64-bit integer)
  • a key-value map of string labels

Labels are used to store metadata about an account, and can also be used for searching. For example, the default player account (in basic config) has the following labels:

Name Value
capital/playerUuid The player UUID
currency default
capital/playerName The player name
capital/playerInfoName money
capital/valueMin 0
capital/valueMax 1000000

This is how we find the accounts for a player: we find accounts with the label capital/player/uuid equal to the player's UUID, then we use other labels like currency to identify which account it is.

In fact, Capital itself does not know what currency is; it's just the default label we use for currencies, but you can change it to anything. It is perfectly fine to delete the currency label.

Plugins that perform Capital transactions should prefer using labels to select accounts for transactions. For example, the pay command is implemented as two label selectors for the source and destination accounts, parameterized with InfoAPI to change labels by players.

Building

On Linux, the phar can be built simply by running make dev/Capital.phar.

Testing

Capital uses integration testing. Run make suites/* to run all integration tests.

Comments
  • Monitor for unusual activities

    Monitor for unusual activities

    Temporarily block the amount in the account if there are abnormal signs such as: a sudden increase in the amount, a negative amount, a continuous increase or decrease in the amount, ..

    opened by NhanAZ 3
  • Vague purpose of dev.md

    Vague purpose of dev.md

    dev.md holds >99% of the official API docs (outside Poggit). I remember one day I spent so long trying to find an official API doc of this plugin. But end up giving up because I omitted dev.md after getting told its purpose.

    I originally wanted to complain the purpose, "This document is for developers who want to contribute to this project" is misleading. However, while writing this issue, I realized that making (peripheral) plugins based on the Capital API can be seen as a contribution to the "project". Therefore, I say its purpose is vague instead of misleading.

    TL;DR

    I do not want to open Poggit to look up the official API doc. But I thought dev.md is for internal dev so I did not read it while looking up on GitHub.

    opened by Endermanbugzjfc 1
  • why when access selector becomes null

    why when access selector becomes null

    Code:

    use SOFe\Capital{Capital, CapitalException, LabelSet};

    class Main extends PluginBase { private $selector;

    protected function onEnable() : void { Capital::api("0.1.0", function(Capital $api) { $this->selector = $api->completeConfig($this->getConfig()->get("selector")); }); } }

    and if i var_dump($this->selector); returned null but if i var_dump in Capital completeConfig it returned Object

    opened by SCGamesNetwork 1
  • Fix minor typo in dev.md

    Fix minor typo in dev.md

    An "s" was missing on line 202 in the file dev.md.

    -  This means the player label is mutable and require real-time updating.
    +  This means the player label is mutable and requires real-time updating.
    
    opened by Swift-Strider 1
  • Capital does not work with libasynql 4.1.1

    Capital does not work with libasynql 4.1.1

    The development build from the 156th in poggit does not work

     [Server thread/CRITICAL]: SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\AwaitException: "Unhandled async exception: SOFe\Capital\Loader\Loader took more than 5 seconds to initialize (blocking classes: SOFe\Capital\Loader\Loader, SOFe\Capital\Transfer\Mod, SOFe\Capital\Capital, SOFe\Capital\Database\Database, SOFe\Capital\Analytics\Mod, SOFe\Capital\Analytics\Single\Mod, SOFe\Capital\Analytics\Top\Mod, SOFe\Capital\Analytics\Top\DatabaseUtils, SOFe\Capital\Migration\Mod, SOFe\Capital\Migration\DatabaseUtils)" (EXCEPTION) in "plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_58655cc4/SOFe/AwaitGenerator/Await" at line 497
    --- Stack trace ---
      #0 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_58655cc4/SOFe/AwaitGenerator/Await(244): SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\Await->reject(object RuntimeException#26410)
      #1 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_58655cc4/SOFe/AwaitGenerator/Await(227): SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\Await->wakeup(object Closure#26400)
      #2 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_58655cc4/SOFe/AwaitGenerator/Await(454): SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#26400)
      #3 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_58655cc4/SOFe/AwaitGenerator/AwaitChild(63): SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\AwaitChild#26327)
      #4 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/Mutex(42): SOFe\Capital\Plugin\_58655cc4\SOFe\AwaitGenerator\AwaitChild->reject(object RuntimeException#26410)
      #5 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(461): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\Mutex->SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\{closure}(object RuntimeException#26410)
      #6 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(217): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->reject(object RuntimeException#26410)
      #7 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(200): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->wakeup(object Closure#21895)
      #8 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(403): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#21895)
      #9 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/AwaitChild(52): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\AwaitChild#26414)
      #10 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(189): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\AwaitChild->resolve(array[2])
      #11 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(472): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await::SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\{closure}(null)
      #12 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(247): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->resolve(null)
      #13 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(224): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->wakeup(object Closure#25171)
      #14 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(456): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#25171)
      #15 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/AwaitChild(52): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\AwaitChild#26420)
      #16 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/AwaitStd(38): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\AwaitChild->resolve()
      #17 pmsrc/src/scheduler/ClosureTask(57): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\AwaitStd->SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\{closure}()
      #18 pmsrc/src/scheduler/TaskHandler(123): pocketmine\scheduler\ClosureTask->onRun()
      #19 pmsrc/src/scheduler/TaskScheduler(141): pocketmine\scheduler\TaskHandler->run()
      #20 pmsrc/src/plugin/PluginManager(498): pocketmine\scheduler\TaskScheduler->mainThreadHeartbeat(int 101)
      #21 pmsrc/src/Server(1815): pocketmine\plugin\PluginManager->tickSchedulers(int 101)
      #22 pmsrc/src/Server(1704): pocketmine\Server->tick()
      #23 pmsrc/src/Server(1065): pocketmine\Server->tickProcessor()
      #24 pmsrc/src/PocketMine(305): pocketmine\Server->__construct(object BaseClassLoader#2, object pocketmine\utils\MainLogger#3, string[8] C:\pmmp\, string[16] C:\pmmp\plugins\)
      #25 pmsrc/src/PocketMine(328): pocketmine\server()
      #26 pmsrc(11): require(string[52] phar://C:/pmmp/PocketMine-MP.phar/src/PocketMine.)
    --- Previous ---
    RuntimeException: "SOFe\Capital\Loader\Loader took more than 5 seconds to initialize (blocking classes: SOFe\Capital\Loader\Loader, SOFe\Capital\Transfer\Mod, SOFe\Capital\Capital, SOFe\Capital\Database\Database, SOFe\Capital\Analytics\Mod, SOFe\Capital\Analytics\Single\Mod, SOFe\Capital\Analytics\Top\Mod, SOFe\Capital\Analytics\Top\DatabaseUtils, SOFe\Capital\Migration\Mod, SOFe\Capital\Migration\DatabaseUtils)" (EXCEPTION) in "plugins/Capital_dev-156.phar/src/SOFe/Capital/Di/Context" at line 78
      #0 (): SOFe\Capital\Di\Context->SOFe\Capital\Di\{closure}()
      #1 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(402): Generator->send(array[2])
      #2 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(215): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\{closure}()
      #3 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(200): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->wakeup(object Closure#21895)
      #4 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/Await(403): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#21895)
      #5 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_469338e7/SOFe/RwLock/_29f5ac4d/SOFe/AwaitGenerator/AwaitChild(52): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\AwaitChild#26414)
      #6 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(189): SOFe\Capital\Plugin\_469338e7\SOFe\RwLock\_29f5ac4d\SOFe\AwaitGenerator\AwaitChild->resolve(array[2])
      #7 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(472): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await::SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\{closure}(null)
      #8 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(247): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->resolve(null)
      #9 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(224): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->wakeup(object Closure#25171)
      #10 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/Await(456): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->wakeupFlat(object Closure#25171)
      #11 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/_7b46c874/SOFe/AwaitGenerator/AwaitChild(52): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\Await->recheckPromiseQueue(object SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\AwaitChild#26420)
      #12 plugins/Capital_dev-156.phar/src/SOFe/Capital/Plugin/_a903796d/SOFe/AwaitStd/AwaitStd(38): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\_7b46c874\SOFe\AwaitGenerator\AwaitChild->resolve()
      #13 pmsrc/src/scheduler/ClosureTask(57): SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\AwaitStd->SOFe\Capital\Plugin\_a903796d\SOFe\AwaitStd\{closure}()
      #14 pmsrc/src/scheduler/TaskHandler(123): pocketmine\scheduler\ClosureTask->onRun()
      #15 pmsrc/src/scheduler/TaskScheduler(141): pocketmine\scheduler\TaskHandler->run()
      #16 pmsrc/src/plugin/PluginManager(498): pocketmine\scheduler\TaskScheduler->mainThreadHeartbeat(int 101)
      #17 pmsrc/src/Server(1815): pocketmine\plugin\PluginManager->tickSchedulers(int 101)
      #18 pmsrc/src/Server(1704): pocketmine\Server->tick()
      #19 pmsrc/src/Server(1065): pocketmine\Server->tickProcessor()
      #20 pmsrc/src/PocketMine(305): pocketmine\Server->__construct(object BaseClassLoader#2, object pocketmine\utils\MainLogger#3, string[8] C:\pmmp\, string[16] C:\pmmp\plugins\)
      #21 pmsrc/src/PocketMine(328): pocketmine\server()
      #22 pmsrc(11): require(string[52] phar://C:/pmmp/PocketMine-MP.phar/src/PocketMine.)
    --- End of exception information ---
    
    opened by Nerahikada 2
  • /richest does not work with SQLite

    /richest does not work with SQLite

    In the SQLite database, the metrics displayed in the rankings are not updated after the first account update. (If recompute-frequency is set to 0, the metrics will be updated.)

    opened by Nerahikada 2
  • Large volume of transactions causes memory depletion

    Large volume of transactions causes memory depletion

    If the database server is slow and takes a long time to process transactions, attempting to process a large number of transactions will ~~create a large number of connections and~~ cause the server to crash due to lack of memory.

    Using slow database, you can reproduce it with code like this

    use SOFe\Capital\{Capital, CapitalException, LabelSet};
    
    Capital::api("0.1.0", function(Capital $api){
        $this->selector = $api->completeConfig(["currency" => "money"]);
    });
    
    $this->getScheduler()->scheduleRepeatingTask(new ClosureTask(function(){
        foreach($this->getServer()->getOnlinePlayers() as $player){
            Capital::api("0.1.0", function(Capital $api) use ($player){
                yield from $api->addMoney($this->getName(), $player, $this->selector, 1, new LabelSet([]));
            });
        }
    }), 1);
    
    wontfix 
    opened by Nerahikada 3
  • Add a method where you can use the player’s balance

    Add a method where you can use the player’s balance

    Currently there is no way to make Player A pay Player B depending on its balance (ex: a percentage of Player A) without causing a race condition. I would suggest having some parameter where it accepts a promise and that in the first argument it has the player A balance. Example:

    $promise = function(int $balance) use($percentage){
        return $balance * $percentage / 100;
    };
    yield from $capital->payWithBalance(
        "SellHeads",
        $player1,
        $player2,
        $this->selector,
        $promise, //This could also be async just like `Capital::api()`
        new LabelSet(["reason" => "Claimed head"])
    );
    
    opened by JavierLeon9966 1
Owner
Jonathan Chan Kwan Yin
a.k.a. SOFe, @chankyin, @PEMapModder
Jonathan Chan Kwan Yin
Economy made easy for Minecraft: Bedrock

BedrockEconomy Economy made easy for Minecraft Bedrock Commands Name Description Usage Permission balance Show your and others balance balance [player

null 33 Oct 24, 2022
Cool economy plugin for PM-like servers. API included.

Economy Description Cool and easy to use economy plugin API: 2.0.0 Plugin version: 1.0.0 Default money value on first join: 1000 (can be changed in co

Artem Turov 0 Feb 4, 2022
Lightweight PHP wrapper for OVH APIs. That's the easiest way to use OVH.com APIs in your PHP applications.

This PHP package is a lightweight wrapper for OVH APIs. That's the easiest way to use OVH.com APIs in your PHP applications.

OVHcloud 263 Dec 14, 2022
A simple way to know if you are on the list of major security breaches like "HIBP", but it is specific for Iran.

Leakfa.com A simple way to know if you are on the list of major security breaches like "HIBP", but it is specific for Iran. Service content This produ

Leakfa 100 Nov 20, 2022
A simple but scalable FFA Practice Core featuring one Game Mode & Vasar PvP aspects.

A simple but scalable FFA Practice Core featuring one Game Mode & Vasar PvP aspects. An example of this Plugin can be found in-game at ganja.bet:19132!

null 6 Dec 7, 2022
PHP 5.3+ Extensible Dumper

Ladybug: PHP 5.3+ Extensible Dumper Ladybug provides an easy and extensible var_dump / print_r replacement for PHP 5.3+ projects. Any PHP variable, ob

Raul Fraile 442 Nov 6, 2022
Zem contact reborn - An extensible HTML form mailer plugin for Textpattern CMS.

com_connect Contents Introduction Installing and upgrading Migrating from zem_contact_reborn Usage Tags com_connect tag com_connect_text tag com_conne

Textpattern CMS 23 Dec 8, 2021
Hoa is a modular, extensible and structured set of PHP libraries

Hoa is a modular, extensible and structured set of PHP libraries. Moreover, Hoa aims at being a bridge between industrial and research worlds. Hoa\Ust

Hoa 403 Dec 20, 2022
A simple Object Oriented wrapper for Linear API, written with PHP.

PHP Linear API A simple Object Oriented wrapper for Linear API, written with PHP. NOTE You should take a look Linear GraphQL API Schema for all nodes

Mustafa KÜÇÜK 6 Sep 2, 2022
Traits used primarily in the v6 package but also available as a helper package for applications

Phalcon Traits This package contains traits with methods that are used for Phalcon v6 onward. It can also be useful to others that want short snippets

The Phalcon PHP Framework 5 Oct 7, 2022
A new plugin like EconomyAPI but with a different mode

A new plugin like EconomyAPI but with a different mode

null 1 Dec 13, 2021
This is wegare tools but all-in-one installer only, exclude GUI

All In One Installer for Wegare Tools This is wegare tools, but this is all-in-one. Here is the source https://github.com/wegare123?tab=repositories I

Helmi Amirudin 3 Jul 29, 2022
Wordpress Plugin Boilerplate but Powered with examples and a generator!

WordPress Plugin Boilerplate Powered WordPress Plugin Boilerplate Powered is a complete foundation for building your WordPress plugins following PSR-4

WordPress Plugin Boilerplate Powered 604 Dec 24, 2022
Disclaimer: The documentation of this plugin is English at the moment, but I might go for Latin later down the line, just for the fun of it.

Quiritibus Plugin This repository is storing the custom plugin developed for the Quiritibus Latin Magazine website, currently being developed at: http

Alkor András 1 Jan 19, 2022
Inquirer.js clone but for PHP.

inquirer-php (immature) This aims to be something equivalent-ish to Inquirer.js or python-inquirer. Status This is in a very immature status — please

Aarón Fas 3 Apr 28, 2022
Magento commands to find translations that are present in one CSV file but not in another, and to translate CSV dicts with DeepL

Hyvä Themes - Magento translation CSV comparison command hyva-themes/magento2-i18n-csv-diff This module adds the bin/magento i18n:diff-csv and i18n:tr

Hyvä 6 Oct 26, 2022
Plateforme de la communauté Devscast dans le but d'apprendre, échanger et réseauter

Devscast Community Platform The Devscast Community Platform is for those who want to impact the community by creating content around their passions, s

Devscast 11 Dec 19, 2022
🦭 Kirby, but headless only – KQL with bearer token, Express-esque middlewares & more

Kirby Headless Starter ℹ️ Send a Bearer test authorization header with a request to the live playground to test this headless starter. This starter ki

Johann Schopplich 36 Dec 28, 2022
Custom torn signatures, like cheds ones, but with your own graphics.

torn-custom-signatures Basic Live signature creation script for Torn. Prerequesites: A file containing the apikeys in an array named as FACTION_ID-api

Dimitris Valilis 4 Nov 23, 2022