Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - PSL

#1
If class B extends Sqoin (i.e. class B inherits from class Sqoin), then inside class B you can directly use this.get(...) to get all injected modules

class B extends Sqoin {
constructor() {
local logger = get("Logger");
logger.log("B");
}
}

This usage, achieved by "inheriting the Sqoin class," is equivalent to giving Class B a direct access to the dependency repository. Class B automatically inherits all of Sqoin's dependency management capabilities, such as obtaining singletons and factory instances, and passing dynamic parameters (this.get("UserService", {id = 1})). It's like moving the dependency injection "toolbox" directly into Class B, making it more convenient to use.
#2
Currently implementing a flexible injection method of default parameters + dynamic parameters.

When registering a dependency, you can set a set of default configurations (for example, presetting the default output format for a logging tool); and when using the dependency, you can pass in new parameters at any time (for example, temporarily changing the output format to debug mode).
Dynamically passed parameters automatically override the default configuration, preserving the default settings while also adapting to temporary requirements in different scenarios. For example, you might use a regular database when registering a user service, but dynamically pass parameters to a test database during a subsequent call without having to modify the original registration rules. This provides flexibility and convenience.

module.factory("Logger", function(sqoin, args) {
return Logger(args.id);
}, {
id = 1
});

local logger1 = Sqoin.get("Logger");
local logger2 = Sqoin.get("Logger", {
id = 2
});

This code demonstrates the "default parameter + dynamic parameter" injection effect in the factory pattern:
1. When registering a Logger as a factory, default parameters are set via {id = 1}, serving as the base configuration for instance creation.
2. When logger1 is first retrieved without parameters, a Logger instance is created using the default parameters id = 1.
3. When logger2 is retrieved a second time with {id = 2}, the dynamic parameters override the default values, creating a new instance with id = 2.

Because of the factory pattern, each get call generates a new instance, and dynamic parameters take effect in real time, making it suitable for scenarios requiring differently configured instances.
#3
https://github.com/leitingzi/vcmp_server.git
My repository contains the core code for dependency injection and a test server that can be run.
#4
This Squirrel code implements a simple dependency injection (DI) framework with the following core features:

1. Provides a Module class for defining dependency bindings, supporting two binding types: single (singleton) and factory (factory). Register types and corresponding providers through the single() and factory() methods respectively.
2. Sqoin serves as the framework entry point and provides singleton context access (getInstance()), module loading (loadModules()), and instance acquisition (get()) functions through static methods.
3. SqoinContext is the core of the context, responsible for managing modules, storing singleton and factory registration information, and obtaining instances by type through the get() method (the singleton is created and cached by the provider when it is first obtained, and the factory creates a new instance each time it is called)

The overall dependency registration and resolution mechanism is implemented, which can be used to manage object dependencies in the server.

class Logger {
    function log(message) {
        print("Log: " + message);
    }
}

class UserRepository {
    logger = null;

    constructor(logger) {
        this.logger = logger;
    }

    function getUser(id) {
        this.logger.log("Getting user with id: " + id);
        return {
            id = id,
            name = "User " + id
        };
    }
}

class UserService {
    repo = null;
    logger = null;

    constructor(repo, logger) {
        this.repo = repo;
        this.logger = logger;
    }

    function getUserInfo(id) {
        this.logger.log("Fetching user info");
        return this.repo.getUser(id);
    }
}

This Squirrel code defines three business classes, forming a simple user information processing chain:
1. Logger class: Provides basic logging functionality, printing messages via the log method.
2. UserRepository class: Responsible for acquiring user data. Its constructor relies on Logger. It uses the getUser method to query user information based on ID and log it.
3. UserService class: Serves as the business service layer, relying on UserRepository and Logger. It encapsulates the user information acquisition process via the getUserInfo method, logging before calling repository layer methods.

The three collaborate through dependencies, embodying the layered design concept (log component, data access layer, business service layer), and can be combined with the dependency injection framework to manage dependencies.

local userModule = Module(function(module) {
        module.single("Logger", function(sqoin) {
            return Logger();
        });

        module.single("UserRepository", function(sqoin) {
            return UserRepository(sqoin.get("Logger"));
        });

        module.factory("UserService", function(sqoin) {
            return UserService(sqoin.get("UserRepository"), sqoin.get("Logger"));
        });
    });

This Squirrel code defines a dependency injection module userModule, which is used to configure the instance creation rules of each business class:
1. The configuration function is passed to the Module constructor, and the Logger and UserRepository are registered as singletons using the single method:
    1. The Logger instance is created directly using the no-argument constructor.
    2. The UserRepository depends on the Logger and constructs itself after obtaining the Logger instance through the dependency injection container.
2. The UserService is registered as a factory using the factory method: Each time a new UserService is constructed, the container retrieves the UserRepository and Logger instances.

This module declares dependencies and provides instance creation and dependency management rules for the previously defined Logger, UserRepository, and UserService, allowing them to be loaded and used by the injection framework.

local modules = [userModule];

Sqoin.loadModules(modules);

local userService1 = Sqoin.get("UserService");
local userService2 = Sqoin.get("UserService");

userService1.getUserInfo(123);
userService2.getUserInfo(456);

This Squirrel code example demonstrates the use of the dependency injection framework:
1. First, the previously defined userModule is added to the modules array. Sqoin.loadModules is used to load the module, completing dependency registration.
2. Sqoin.get("UserService") is called twice to obtain service instances (because UserService is registered as a factory, two different instances are generated).
3. The getUserInfo method is called on each UserService instance, passing in different IDs (123 and 456) to retrieve user information.

Running this code triggers logging and user data querying, demonstrating how the dependency injection framework manages object creation and dependency propagation. It also demonstrates the factory pattern's characteristic of generating a new instance each time a request is made.

#5
The code uses `org.json.JSONObject` to handle JSON data, but the JSON dependency is not included in the Maven `pom.xml` (you named it `Depidence.xml`, the standard name should be `pom.xml`). Direct compilation will result in a `ClassNotFoundException`
#6
This Squirrel code defines the `When` class and `when` function, enabling conditional logic functionality. The `When` class includes methods like `is` (equal to) and `isNot` (not equal to). If conditions are met, corresponding actions are executed and results are recorded, with only the first matching action triggered. Otherwise, all non-matching cases are handled, and the final result is returned.

class When {
    value = null;
    found = false;
    result = null;

    constructor(value) {
        this.value = value;
    }

    function is(expected, action) {
        if (!found && value == expected) {
            found = true;
            result = action();
        }
        return this;
    }

    function isNot(expected, action) {
        if (!found && value != expected) {
            found = true;
            result = action();
        }
        return this;
    }

    function isType(typeName, action) {
        if (!found && typeof value == typeName) {
            found = true;
            result = action();
        }
        return this;
    }

    function isNull(action) {
        if (!found && value == null) {
            found = true;
            result = action();
        }
        return this;
    }

    function inRange(min, max, action) {
        if (!found && value >= min && value <= max) {
            found = true;
            result = action();
        }
        return this;
    }

    function match(condition, action) {
        if (!found && condition(value)) {
            found = true;
            result = action();
        }
        return this;
    }

    function otherwise(action) {
        if (!found) {
            result = action();
        }
        return result;
    }
}

function when(value) {
    return When(value);
}

Here is an example
local x = 65;
local result = when(x)
    .isNull(@()"is Null")
    .isType("float", @()"Not Float")
    .is(100, @()"Max")
    .inRange(0, 35, @()"0~35")
    .inRange(35, 70, @()"35~70")
    .match(@(v) v * 2 > 150 && v < 80, @()"75~80")
    .otherwise(@()">80");

print(result); // out 0~35
#7
PassDataToServer

I can use the this function to send this table, but using this function in script uninstallation events is invalid。

What I can think of now is to use a client timer to implement it
#8
The player's client has a table that stores the state of the GUI. I hope that when the player quits, this table can be sent to the server and stored on the server, so that when the player logs in again, the table can be transmitted to restore the previous GUI state.
#9
Hi Habi,How to send the last data to the server using client-side scripts when a player quits, such as after entering /q?

I tried to perform a remote call to return data during the player exit event, but there was no response
#10
Community Plugins / Re: New Python Plugin
May 12, 2025, 05:08 AM
Well done! This plugin supports functional expansion, bringing a great deal of possibilities to VC-MP servers. I'm looking forward to seeing more developers creating interesting gameplay based on it!
#11
After my testing, this problem has been solved
#12
Hello, Hibi.
An error occurred with GetRemoteValue("print")("abc") on the client, typeof( GetRemoteValue("print")("abc") ) This returns type null.
When I use Exec(GetRemoteValue("print")("Have a nice day")) the client throws an error PeerExec: superblob expected but got null

    local userData = CallRemoteFunc( GetRemoteValue("print"),"123");
    Exec( userData );  //This is effective
#13
Hi, Habi.
I have been using the NPC plug-in you developed. The appearance of NPC has enriched the gameplay of the game. I would like to express my heartfelt thanks to you. After a period of use, I found that if you can add some specific functions to the plug-in, it may further improve its functionality and practicality. I would like to add some functions related to getting properties. I made a feature that fits my needs. Although I have already built it, I still want to integrate it into the plugin.
function OnPlayerStreamIn(playerid)
{
    print("npctest: OnPlayerStreamIn(playerid="+playerid+")\n");

//When you find a player, save player attributes first
getPlayerImmunity(playerid);
}

function OnPlayerStreamOut(playerid)
{
    print("npctest: OnPlayerStreamOut(playerid="+playerid+")\n");

//Here I have written a function that empties the player's attributes
}

function onGetImmunity(playerID, immunity){
print(GetPlayerName(playerID)+"'s Immunity: "+immunity+" \n");

//I store the data in a table and use the following function to get it when needed
}

function getPlayerImmunity(playerID){
//Get the player attributes I want from the table
}

function toGetPlayerImmunity(playerID){
RFC("getPlayerImmunity")(playerID, GetMyID());
}

//server
function getPlayerImmunity(playerID, npcID){
local plr = FindPlayer(playerID);
if(plr){
RFC(npcID, "onGetImmunity")(plr.ID, plr.Immunity);
}
}

Now you can use getPlayerImmunity to get the player's immunity in NPC scrpit. I've done a lot of things with this approach, such as player transparency, player cash, player deposits, whether a player can be attacked, player IP, UID, etc, Your varholder plugin has also helped me a lot.

I understand that adding these functions may increase your workload, but I believe that these new functions will not only meet my personal needs, but may also benefit more users, thus further increasing the value and popularity of the plug-in.
If you are willing to consider my request, I would be more than happy to provide you with more information about the specific details and usage scenarios of these functions to help you better understand my requirements. If there is anything I can do to help during the development process, such as testing new features, please feel free to ask and I will assist in any way I can.
Thank you again for developing such an excellent plugin and look forward to hearing from you.
#14
I can't wait to use it. Well done, Habi bro!
#15
Thank you. The code you provided worked