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

Topics - PSL

#1
Script Showroom / Modular Support
Apr 14, 2026, 11:07 AM
This is a lightweight, modular management framework designed specifically for the Squirrel language. With zero dependencies and ready to use right out of the box, it comprehensively resolves the issues inherent in traditional single-script architectures—such as disorganization, difficulty in maintenance, lack of hot-updating capabilities, and event conflicts.

Through a unified module manager, the framework facilitates module loading, unloading, dependency management, lifecycle control, automatic global event dispatch, and secure timer isolation—thereby enabling your server scripts to truly achieve an engineered, modular, and extensible architecture.

  • Each module resides in a separate file with its own isolated scope, ensuring no mutual interference and resulting in a clean, easily maintainable code structure.
  • Supports single-module loading, batch loading, and dependency-aware loading; automatically detects whether a module has already been loaded to prevent redundant execution.
  • Features built-in `onScriptLoad` and `onScriptUnload` lifecycle hooks, which execute automatically whenever a module is loaded or unloaded.
  • Covers events across all scenarios—including server, player, vehicle, item, command, and chat interactions—with all modules automatically listening for these events, eliminating the need for manual hook binding.
  • Includes a dedicated `newTimer` function that binds timers directly to their respective modules; timers are automatically destroyed when a module is unloaded, effectively preventing memory leaks.
  • Enables cross-module function calls and variable access via `getModule()`, facilitating seamless functional interoperability between modules.
  • Supports the unloading of individual modules as well as a one-click option to clear all modules, allowing for hot-reloading without requiring a server restart.
  • Avoids polluting the global scope and leaves native logic unmodified; integration is straightforward and compatible with all standard Squirrel environments.

Here is a simple example.

function onPlayerJoin(player) {
MessagePlayer("[#FFFF00]Hello " + player.Name, player);
}

function onScriptLoad() {
print("onScriptLoad: " + moduleName);
}

function onScriptUnload() {
print("onScriptUnload: " + moduleName);

a.Delete();
}

function hello(value) {
print("hello " + value);
}

a <- newTimer("hello", 1000, 0);

Place the script file into the "module" folder, then load the filename to add the script's functionality to the server.

ModuleManager.load("testModule");

#2
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.

#3
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
#4
.so: cannot open shared object file: No such file or directory
Failed to load plugin: squirrel04rel64


.
├── announce.log
├── plugins
│   ├── announce04rel64.so
│   ├── mysql04rel64.so
│   ├── sockets04rel64.so
│   └── squirrel04rel64.so
├── scripts
│   └── main.nut
├── server64
├── server.cfg
└── server_log.txt

gamemode Default
plugins announce04rel64 squirrel04rel64
port 8192
sqgamemode scripts/main.nut

What kind of question is that
#5
How to output properties and values in a player class?
        if(cmd=="getglobal")
{
MessagePlayer("[#00FF00]Your Global: ",player);
foreach(i,j in state[player.ID])
{
MessagePlayer("[#00FF00]"+i+" = "+j,player);
}
}


AN ERROR HAS OCCURED [_nexti failed]

CALLSTACK
*FUNCTION [onPlayerCommand()] store/main.nut line [1173]

LOCALS
[j] NULL
[i] NULL
[text] NULL
[cmd] "getglobal"
[player] INSTANCE
[this] TABLE
#6
I think in...squirrel04rel64.dll To add some functions.
I successfully compiled through the source code, but I do not know how to add a custom function in the source code, I want to add a function to disable the player key in the source code, how should I write?
#7
I tried to compile the makefile file in vscode, but the following problem occurred.Is there something wrong with the file itself?

C:/ProgramData/chocolatey/lib/make/tools/install/bin/make.exe BITCOUNT=32 BUILDTYPE=rel xbuild
make[1]: Entering directory 'C:/Users/Administrator/Desktop/stormeus-0.4-announce-c1f737aaddce/0.4-announce' The command syntax is incorrect.
make[1]: *** [Makefile:56: objdir/rel32/./main.o] Error 1
make[1]: Leaving directory 'C:/Users/Administrator/Desktop/stormeus-0.4-announce-c1f737aaddce/0.4-announce'
make: *** [Makefile:32: build32] Error 2

I can compile the following normally:
main.cc
#include <stdio.h>

int main(int argc, char*argv[]) {
    printf("test\n");
    return 0;
}

Makefile
.PHONY: all clean

CC := gcc
CXX := g++
CFLAGS :=
CXXFLAGS := -gdwarf-4
Target := main

SRCS += $(wildcard *.cc)
OBJS := $(patsubst %.cc, %.o, ${SRCS})

all: $(Target)

$(Target): $(OBJS)
    $(CXX) $(CXXFLAGS) $(OBJS) -o $@

%.o: %.cc
    $(CXX) $(CXXFLAGS) -c $? -o $@

clean:
    rm -rf $(OBJS) $(Target)

#8
Client Scripting / RGB Color Gradient
May 05, 2024, 03:01 AM
Do you want your text or images, or other gui components to have RGB gradients?
The following code can get you inspired, but you can also use it in between.
The gradient order is white red orange yellow green cyan blue purple.

local serverlogor=255,serverlogog=255,serverlogob=255;
local rgblabel=null;

function Script::ScriptLoad()
{
rgblabel=GUILabel();
rgblabel.Pos=VectorScreen(250,450);
rgblabel.FontSize=40;
rgblabel.Text="Very cool gradient text";
rgblabel.TextColour=GetGradientRGB();
}

function Script::ScriptProcess()
{
UpdateRGB();
rgblabel.TextColour=GetGradientRGB();
}

function GetGradientRGB(alpha=255)
{
    return Colour(serverlogor,serverlogog,serverlogob,alpha);
}

function UpdateRGB()
{
    /* red to purple
    if(serverlogor==255&&serverlogog<255&&serverlogob==0)
    {
        serverlogog+=1;
        if(serverlogog==255) serverlogor-=1;
    }
    else if(serverlogor<255&&serverlogog==255&&serverlogob==0)
    {
        serverlogor-=1;
        if(serverlogor==0) serverlogob+=1;
    }
    else if(serverlogor==0&&serverlogog==255&&serverlogob>0)
    {
        serverlogob+=1;
        if(serverlogob==255) serverlogog-=1;
    }
    else if(serverlogor==0&&serverlogog<255&&serverlogob==255)
    {
        serverlogog-=1;
        if(serverlogog==0) serverlogor+=1;
    }
    else if(serverlogor>0&&serverlogog==0&&serverlogob==255)
    {
        serverlogor+=1;
        if(serverlogor==255) serverlogob-=1;
    }
    else if(serverlogor==255&&serverlogog==0&&serverlogob<255)
    {
        serverlogob-=1;
    }
    */

    // white to purple
    if(serverlogor==255&&serverlogog==255&&serverlogob==255)
    {
        serverlogog-=1;
        serverlogob-=1;
    }
    else if(serverlogor==255&&serverlogog<255&&serverlogob<255&&serverlogob!=0)
    {
        serverlogog-=1;
        serverlogob-=1;
        if(serverlogog==0&&serverlogob==0) serverlogog+=1;
    }
    else if(serverlogor==255&&serverlogog<255&&serverlogob==0)
    {
        serverlogog+=1;
        if(serverlogog==255) serverlogor-=1;
    }
    else if(serverlogor<255&&serverlogog==255&&serverlogob==0)
    {
        serverlogor-=1;
        if(serverlogor==0) serverlogob+=1;
    }
    else if(serverlogor==0&&serverlogog==255&&serverlogob>0)
    {
        serverlogob+=1;
        if(serverlogob==255) serverlogog-=1;
    }
    else if(serverlogor==0&&serverlogog<255&&serverlogob==255)
    {
        serverlogog-=1;
        if(serverlogog==0) serverlogor+=1;
    }
    else if(serverlogor>0&&serverlogog==0&&serverlogob==255)
    {
        serverlogor+=1;
        if(serverlogor==255) serverlogog+=1;
    }
    else if(serverlogor==255&&serverlogog<255&&serverlogob==255)
    {
        serverlogog+=1;
        if(serverlogog==255)
        {
            serverlogog-=1;
            serverlogob-=1;
        }
    }
}
#9
When your script goes wrong, the system finds the wrong code, deletes it, and then restarts the server.
function ReloadServer()
{
    local loaded=[];
    for(local i=0;i<100;i++)
    {
        local plr=FindPlayer(i);
        if(plr)
        {
            loaded.append(plr.ID);
            if(plr.Vehicle) plr.Eject();

            onPlayerPart(plr,0);
        }
    }

    onScriptUnload();
    onServerStop();
    dofile("scripts/main.nut");
    onScriptLoad();
    onServerStart();

    for(local i=0;i<loaded.len();i++)
    {
        local plr=FindPlayer(loaded[i]);
        if(plr)
        {
            onPlayerJoin(plr);
            onPlayerRequestClass(plr,plr.Class,plr.Team,plr.Skin);
            if(plr.IsSpawned==true) onPlayerSpawn(plr);
        }
    }
    AnnounceAll("~p~Server Reload!",3);
}

function ReadTextFromFile(path)
{
    local f=file(path,"rb"),s ="",n=0;
    f.seek(0,'e');
    n=f.tell();
    if(n==0) return s;
       
    f.seek(0,'b');
    local b=f.readblob(n+1);
    f.close();
    for(local i=0;i<n;++i) s+=format(@"%c",b.readn('b'));
    return s;
}

function WriteTextToFile(path,text)
{
    local f=file(path,"wb+"),s="";
    f.seek(0,'e');
    foreach(c in text) f.writen(c,'b');
    f.close();
}

function errorfixer(str)
{
local stackinfo,stacktrace="[Error]\n"+str+"\n[Functions]",locals="\n[Locals]",linearr=[];
for(local i=2;stackinfo=getstackinfos(i);i++)
{
stacktrace+="\n["+stackinfo["func"]+"()] "+stackinfo["src"]+" ["+stackinfo["line"]+"]";
linearr.append(stackinfo["line"].tointeger());
foreach(idx,val in stackinfo["locals"]) locals+="\n["+stackinfo["func"]+"]"+idx+", Value="+val+"";
}
print(stacktrace+locals);

    local script=ReadTextFromFile("scripts/main.nut");
    local arr=split(script,"\n"),data="";
    for(local i=1;i<arr.len()+1;i++)
    {
        local find=false;
        for(local ii=0;ii<linearr.len();ii++)
        {
            if(i==linearr[ii].tointeger())
            {
                find=true;
                break;
            }     
            if(find==false)
            {
                data+=arr[i-1];
                break;
            }
        }
    }
    WriteTextToFile("scripts/main.nut",data);
    ReloadServer();
}
seterrorhandler(errorfixer);
#10
Script Showroom / BindKey Process System
Mar 11, 2024, 12:57 PM
When the player consistently presses a bound key, the script continues to execute the key's code. How is this done, see the code below.
The code has been tested and is accurate, although you can customize the code to suit your server.
class PlayerClass //Create two items here, one to store buttons pressed by the player and the other to keep repeating the timer
{
    keytimer=null;
    keytable=null;
}
function onScriptLoad()
{
    state<-array(100,null);
    //Here are the keys on the test keyboard
    Key_I<-BindKey(true,0x49,0,0);
    Key_J<-BindKey(true,0x4A,0,0);
    Key_K<-BindKey(true,0x4B,0,0);
    Key_L<-BindKey(true,0x4C,0,0);
}
function onPlayerJoin(player)
{
    state[player.ID]=PlayerClass(player.Name);
}
function onPlayerPart(player,reason)
{
if(state[player.ID].keytimer!=null) //When the player exits, delete these two things
{
state[player.ID].keytimer.Delete();
state[player.ID].keytimer=null;
state[player.ID].keytable.clear();
state[player.ID].keytable=null;
}
    state[player.ID]=null;
}
function onKeyDown(player,key)
{
    //When you press the key, the corresponding text will be displayed
    if(key==Key_I) Message("Key: I");
    if(key==Key_J) Message("Key: J");
    if(key==Key_K) Message("Key: K");
    if(key==Key_L) Message("Key: L");
    AddKeyTable(player.ID,key); //Saves the key that the player presses
}
function onKeyUp(player,key)
{
    RemoveKeyTable(player.ID,key); //Delete the key saved by the player
}
function AddKeyTable(i,key)
{
    local plr=FindPlayer(i);
    if(plr)
    {
        if(state[plr.ID].keytable==null) state[plr.ID].keytable={}; //The first time the key is pressed, the table is created

        if(state[plr.ID].keytable.rawin(key))
        {
        }
        else state[plr.ID].keytable.rawset(key,key); //If the key is not in the table, add it

        if(state[plr.ID].keytimer==null) //If the repetition timer is not created, create it
        {
            state[plr.ID].keytimer=NewTimer("onKeyProcess",10,0,plr.ID);
        }
    }
}

function RemoveKeyTable(i,key) //Here is the delete key function
{
    local plr=FindPlayer(i);
    if(plr)
    {
        if(state[plr.ID].keytable!=null)
        {
if(state[plr.ID].keytable.rawin(key)) //If the key exists in the player's table
{
state[plr.ID].keytable.rawdelete(key); //Delete it
if(state[plr.ID].keytable.len()==0)
{
state[plr.ID].keytable=null; //If there are no keys in the table, delete the table
if(state[plr.ID].keytimer!=null) //Also delete timer
{
state[plr.ID].keytimer.Delete();
state[plr.ID].keytimer=null;
}
                }
            }
        }
    }
}
function onKeyProcess(i)
{
    local plr=FindPlayer(i);
    if(plr)
    {
        if(state[plr.ID].keytable!=null)
        {
            if(state[plr.ID].keytable.len()>0)
            {
                local nokey=0;
                for(local i=0;i<state[plr.ID].keytable.len()+1000;i++) //Create a loop to get the keys in the player's store table
                {
                    if(state[plr.ID].keytable.rawin(i))
                    {
                        local key=state[plr.ID].keytable.rawget(i);
                        nokey=0;
                        onKeyDown(plr,key); //Execute this key
                    }
                    else nokey+=1;

                    if(nokey>=10) break; //The 10 here is the number you set when you create the number of binding keys
                }
      }
        }
    }
}
#11
I ran some function scripts using dofile, Now I want to deactivate the previous dofile script, what do I do?
#12
I am trying to upgrade the server version from 04rel006 to 04rel004. I found that none of the custom weapons I added were working. Invalid weapon data is displayed when entering the server. This is true not only for weapons, but also for custom vehicles.
The server version I am using is: https://forum.vc-mp.org/index.php?topic=4727.0, The plug-in used is https://forum.vc-mp.org/index.php?topic=33.0  plugins for scripts inside.

This is the weapon that went wrong.
https://file.io/VmW3C2wBixJe
#13
I want to print the font in green color, what should I do?
#14
I have a module here, in the single game can open cannons and can fire machine guns, you can only cannons in the server, can you help me to see what is the reason, this is xml。

<?xml version="1.0" encoding="ASCII"?>
<vehicle>
    <basic>
        <type>car</type>
        <name>NASCAR 48</name>
        <anims>null</anims>
        <comprules>20479</comprules>
        <extraflags>40</extraflags>
        <wheelmodel>249</wheelmodel>
        <wheelscale>0.870000</wheelscale>
        <immunity>255</immunity>
    </basic>

    <aidata>
        <class>ignore</class>
        <freq>10</freq>
        <level>7</level>
    </aidata>

    <colors>
        <carcol>7,53</carcol>
        <carcol>3,40</carcol>
        <carcol>35,53</carcol>
        <carcol>40,75</carcol>
        <carcol>42,2</carcol>
        <carcol>46,6</carcol>
    </colors>

    <audio>
        <enginefarsample>274</enginefarsample>
        <enginenearsample>10</enginenearsample>
        <hornsample>0</hornsample>
        <hornfreq>26513</hornfreq>
        <sirensample>0</sirensample>
        <sirenfreq>9600</sirenfreq>
        <doorsounds>1</doorsounds>
    </audio>

    <handling>
        <mass>1600000.000000</mass>
        <percentsubmerged>-1</percentsubmerged>
        <steeringlock>28.000000</steeringlock>
        <seatoffset>0.600000</seatoffset>
        <damagemultiplier>-0.300000</damagemultiplier>
        <value>90000</value>
        <flags>0000A181</flags>

        <dimensions>
            <x>2.000000</x>
            <y>4.500000</y>
            <z>1.500000</z>
        </dimensions>

        <centreofmass>
            <x>0.000000</x>
            <y>0.000000</y>
            <z>-1.00000</z>
        </centreofmass>

        <traction>
            <multiplier>1.500000</multiplier>
            <loss>0.700000</loss>
            <bias>0.500000</bias>
        </traction>

        <transmission>
            <numofgears>5</numofgears>
            <maxspeed>300.000000</maxspeed>
            <acceleration>50.000000</acceleration>
            <drivetype>4</drivetype>
            <enginetype>P</enginetype>
        </transmission>

        <brakes>
            <deceleration>30.000000</deceleration>
            <bias>0.480000</bias>
            <abs>0</abs>
        </brakes>

        <suspension>
            <forcelevel>1.000000</forcelevel>
            <dampening>0.100000</dampening>
            <upperlimit>0.250000</upperlimit>
            <lowerlimit>-0.100000</lowerlimit>
            <bias>0.500000</bias>
            <antidive>0.500000</antidive>
        </suspension>

        <lights>
            <front>1</front>
            <rear>1</rear>
        </lights>
    </handling>

    <weaponlist>
        <weapon>
            <type>machinegun</type>
            <model>none</model>
           
            <hotkeys>
                <dockkey>0,0,0</dockkey>
                <moveupkey>0,0,0</moveupkey>
                <movedownkey>0,0,0</movedownkey>
                <restorekey>0,0,0</restorekey>
                <shootkey>16,16,16</shootkey>
            </hotkeys>
           
            <fireoffset>
                <x>0.5</x>
                <y>0.0</y>
                <z>-0.9</z>
            </fireoffset>

            <armedinfo>
                <movespeed>0</movespeed>
                <middlepos>0.5</middlepos>
           
                <minpos>
                    <x>0.58</x>
                    <y>0.4</y>
                    <z>0.3</z>
                </minpos>
               
                <minrot>
                    <x>-1.57</x>
                    <y>0.0</y>
                    <z>1.57</z>
                </minrot>
            </armedinfo>
        </weapon>

        <weapon>
            <type>machinegun</type>
            <model>none</model>
           
            <hotkeys>
                <dockkey>0,0,0</dockkey>
                <moveupkey>0,0,0</moveupkey>
                <movedownkey>0,0,0</movedownkey>
                <restorekey>0,0,0</restorekey>
                <shootkey>16,16,16</shootkey>
            </hotkeys>
           
            <fireoffset>
                <x>0.5</x>
                <y>0.0</y>
                <z>0.2</z>
            </fireoffset>

            <armedinfo>
                <movespeed>0</movespeed>
                <middlepos>0.5</middlepos>
           
                <minpos>
                    <x>-1.28</x>
                    <y>0.4</y>
                    <z>0.3</z>
                </minpos>
               
                <minrot>
                    <x>-1.57</x>
                    <y>0.0</y>
                    <z>1.57</z>
                </minrot>
            </armedinfo>
        </weapon>

        <weapon>
            <type>machinegun</type>
            <model>none</model>
           
            <hotkeys>
                <dockkey>0,0,0</dockkey>
                <moveupkey>0,0,0</moveupkey>
                <movedownkey>0,0,0</movedownkey>
                <restorekey>0,0,0</restorekey>
                <shootkey>16,16,16</shootkey>
            </hotkeys>
           
            <fireoffset>
                <x>0.5</x>
                <y>0.0</y>
                <z>0.2</z>
            </fireoffset>

            <armedinfo>
                <movespeed>0</movespeed>
                <middlepos>0.5</middlepos>
           
                <minpos>
                    <x>-0.3</x>
                    <y>0</y>
                    <z>0.85</z>
                </minpos>
               
                <minrot>
                    <x>-1.57</x>
                    <y>0.0</y>
                    <z>1.57</z>
                </minrot>
            </armedinfo>
        </weapon>

        <weapon>
            <type>machinegun</type>
            <model>none</model>
           
            <hotkeys>
                <dockkey>0,0,0</dockkey>
                <moveupkey>0,0,0</moveupkey>
                <movedownkey>0,0,0</movedownkey>
                <restorekey>0,0,0</restorekey>
                <shootkey>16,16,16</shootkey>
            </hotkeys>
           
            <fireoffset>
                <x>0.5</x>
                <y>0.0</y>
                <z>0.2</z>
            </fireoffset>

            <armedinfo>
                <movespeed>0</movespeed>
                <middlepos>0.5</middlepos>
           
                <minpos>
                    <x>0.7</x>
                    <y>0</y>
                    <z>0.85</z>
                </minpos>
               
                <minrot>
                    <x>-1.57</x>
                    <y>0.0</y>
                    <z>1.57</z>
                </minrot>
            </armedinfo>
        </weapon>
    </weaponlist>
</vehicle>
#15
Snippet Showroom / Player Vertical Angle
May 29, 2023, 11:18 AM
This client function returns the player's horizontal and vertical angles.
It is used as GetAngle("x"); , returns the same value as player.Angle, and a GetAngle("y"); ", returns the player's vertical Angle. One drawback is that when the player is facing in a positive east-west direction, it is impossible to calculate.

function GetAngle(m)
{
    local angle;
    local a=GUI.ScreenPosToWorld(Vector(GUI.GetScreenSize().X/2,GUI.GetScreenSize().Y/2,1));
    local b=GUI.ScreenPosToWorld(Vector(GUI.GetScreenSize().X/2,GUI.GetScreenSize().Y/2,-1));

    if(m=="x") angle=-atan2(a.X-b.X,a.Y-b.Y);
    if(m=="y") angle=-atan2(b.Y-a.Y,a.Z-b.Z);

    angle=(angle*100).tointeger();
    angle=angle.tofloat()*0.01;
    return angle;
}
#16
How do I disable crouching, I've tried a lot of things like actions, skins, weapon Settings, and it doesn't work very well, my current solution is to modify the firing motion of the weapon, but I want to do it better, like the crouching button doesn't exist.
#17
Client Scripting / Progress bar speedometer
Mar 18, 2023, 08:36 AM
I'm going to bring you a simple, segmented speedometer.You can set the maximum value to adjust the speed limit.It has fade in, fade out, and shake effects.The code has been tested on a blank server and works perfectly.

// ====Server side====
enum StreamType
{
    EnterVehicle=0x01
    ExitVehicle=0x02
}

function onPlayerEnterVehicle(player,vehicle,door)
{
    SendDataToClient(player,StreamType.EnterVehicle,vehicle.ID);
}

function onPlayerExitVehicle(player,vehicle)
{
    SendDataToClient(player,StreamType.ExitVehicle);
}

function SendDataToClient(player,...)
{
    if(vargv[0])
    {
        local byte=vargv[0],len=vargv.len();
        if(1>len) devprint("ToClent <"+byte+"> No params specified.");
        else
        {
            Stream.StartWrite();
            Stream.WriteByte(byte);

            for(local i=1;i<len;i++)
            {
                switch(typeof(vargv[i]))
                {
                    case "integer": Stream.WriteInt(vargv[i]); break;
                    case "string": Stream.WriteString(vargv[i]); break;
                    case "float": Stream.WriteFloat(vargv[i]); break;
                }
            }
           
            if(player==null) Stream.SendStream(null);
            else if(typeof(player)=="instance") Stream.SendStream(player);
            else devprint("ToClient <"+byte+"> Player is not online.");
        }
    }
    else devprint("ToClient: Even the byte wasn't specified...");
}

// ====Client side====
local speedbar1=null;
local speedbar2=null;
local speedtext=null;
local speedveh=null;
local speedalpha=0;

function Script::ScriptLoad()
{
    speedbar1=GUIProgressBar();
    speedbar1.Pos=VectorScreen(GetProportion(1635,"x"),GetProportion(290,"y"));
    speedbar1.Size=VectorScreen(GetProportion(175,"x"),GetProportion(25,"y"));
    speedbar1.StartColour=Colour(255,0,0,255);
    speedbar1.EndColour=Colour(0,255,0,255);
    speedbar1.MaxValue=750;
    speedbar1.Value=750;
    speedbar1.Thickness=GetProportion(2,"y");
    speedbar1.BackgroundShade=0.75;
    speedbar1.Alpha=0;
    speedbar1.RemoveFlags(GUI_FLAG_VISIBLE|GUI_FLAG_BACKGROUND);

    speedbar2=GUIProgressBar();
    speedbar2.Pos=VectorScreen(GetProportion(1635,"x"),GetProportion(325,"y"));
    speedbar2.Size=VectorScreen(GetProportion(175,"x"),GetProportion(25,"y"));
    speedbar2.StartColour=Colour(0,128,255,255);
    speedbar2.EndColour=Colour(255,0,255,255);
    speedbar2.MaxValue=200;
    speedbar2.Value=1;
    speedbar2.Thickness=GetProportion(2,"y");
    speedbar1.BackgroundShade=0.75;
    speedbar2.Alpha=0;
    speedbar2.RemoveFlags(GUI_FLAG_VISIBLE|GUI_FLAG_BACKGROUND);

    speedtext=GUILabel();
    speedtext.Text="xxxxxxxx";
    speedtext.TextColour=Colour(255,255,255,255);
    speedtext.FontName="Helvetica";
    speedtext.FontSize=GetProportion(20,"y");
    speedtext.Pos=VectorScreen(0,GetProportion(25,"y"));
    speedtext.TextAlignment=GUI_ALIGN_LEFT|GUI_ALIGN_TOP;
    speedtext.FontFlags=GUI_FFLAG_BOLD;
    speedtext.Text=""+(speedbar2.Value-1)+" Km/h";
    speedtext.Alpha=0;
    speedtext.RemoveFlags(GUI_FLAG_VISIBLE);

    speedbar2.AddChild(speedtext);
}

function Script::ScriptProcess()
{
    if(speedveh!=null)
    {
        if(speedalpha<255)
        {
            speedalpha+=5;
            speedbar1.Alpha=speedalpha;
            speedbar2.Alpha=speedalpha;
            speedtext.Alpha=speedalpha;
        }

        local speed=((speedveh.Speed.X*speedveh.Speed.X)+(speedveh.Speed.Y*speedveh.Speed.Y)+(speedveh.Speed.Z*speedveh.Speed.Z))*100;
        local a=speed-speedbar2.Value.tointeger();
        if(speedbar2.Value!=speed)
        {   speedbar2.Value=speedbar2.Value+a*0.1;
            speedtext.Text=""+speedbar2.Value.tointeger()+" Km/h";
        }

        local hp=speedveh.Health.tointeger()-250;
        local a=speedbar1.Value.tointeger()-hp;
        if(speedbar1.Value!=speedveh.Health.tointeger()-250) speedbar1.Value=speedbar1.Value-a*0.1;

        if(speed>speedbar2.MaxValue) speedtext.TextColour=Colour(255,0,0,255);
        else speedtext.TextColour=Colour(255,255,255,255);

        if(speed>=25)
        {
            local a=random(-2,2);
            local b=random(-2,2);
            local c=5;
           
            if(speedbar1.Pos.X+a>=1635-c&&speedbar1.Pos.X+a<=1635+c) speedbar1.Pos.X+=a;
            if(speedbar1.Pos.Y+b>=290-c&&speedbar1.Pos.Y+b<=290+c) speedbar1.Pos.Y+=b;
            if(speedbar2.Pos.X+a>=1635-c&&speedbar2.Pos.X+a<=1635+c) speedbar2.Pos.X+=a;
            if(speedbar2.Pos.Y+b>=325-c&&speedbar2.Pos.Y+b<=325+c) speedbar2.Pos.Y+=b;
        }
    }
    else
    {
        if(speedalpha>0)
        {
            speedalpha-=5;
            speedbar1.Alpha=speedalpha;
            speedbar2.Alpha=speedalpha;
            speedtext.Alpha=speedalpha;
        }
        else
        {
            speedbar1.RemoveFlags(GUI_FLAG_VISIBLE);
            speedbar2.RemoveFlags(GUI_FLAG_VISIBLE);
            speedtext.RemoveFlags(GUI_FLAG_VISIBLE);
        }
    }
}

function Server::ServerData(stream)
{
    local type=stream.ReadByte();
    switch(type)
    {
        case 0x01:
        {
            local id=stream.ReadInt();
            speedveh=World.FindVehicle(id);
            speedbar1.AddFlags(GUI_FLAG_VISIBLE);
            speedbar2.AddFlags(GUI_FLAG_VISIBLE);
            speedtext.AddFlags(GUI_FLAG_VISIBLE);
        }
        break;

        case 0x02:
        {
            speedveh=null;
        }
        break;
    }
}

function GUI::GameResize(width,height)
{
    speedbar1.Pos=VectorScreen(GetProportion(1635,"x"),GetProportion(290,"y"));
    speedbar1.Size=VectorScreen(GetProportion(175,"x"),GetProportion(25,"y"));
    speedbar1.Thickness=GetProportion(2,"y");
    speedbar2.Pos=VectorScreen(GetProportion(1635,"x"),GetProportion(325,"y"));
    speedbar2.Size=VectorScreen(GetProportion(175,"x"),GetProportion(25,"y"));
    speedbar2.Thickness=GetProportion(2,"y");
    speedtext.FontSize=GetProportion(20,"y");
    speedtext.Pos=VectorScreen(0,GetProportion(25,"y"));
}

function GetProportion(a,b)
{
    local x=GUI.GetScreenSize().X,y=GUI.GetScreenSize().Y;
    if(b=="x")
    {
        a=(a.tofloat()*x.tofloat())/1920;
        local c=x.tofloat()*(a.tofloat()/x.tofloat());
        return c.tointeger();
    }

    if(b=="y")
    {
        a=(a.tofloat()*y.tofloat())/1080;
        local c=y.tofloat()*(a.tofloat()/y.tofloat());
        return c.tointeger();
    }
}

function random(start,finish)
{
    local r=((rand() % (finish-start))+start);
    return r;
}
#18
Script Showroom / Server Builder
Jan 12, 2023, 09:20 AM
I had a good idea, so I did it, in my continuous testing, no bug happened.
This script helps you create maps, vehicles, pickups, and checkpoints and you can export the code.
There is a manual in it, my English is not good, there may be some grammar problems.
Download address of the server: https://www107.zippyshare.com/v/f6yh7gqq/file.html

#19
General Discussion / Report pirated servers
Nov 06, 2022, 10:33 AM
My favorite server is pirated,I may not tolerate such a thing。See the main list with multiple pirate servers and more people playing。These are the IP addresses of the two pirate servers: 61.136.162.163:8100。By some means, they obtained the server's script file and started the service under their name。
This is the IP address of the genuine server: 182.61.50.31:8100, and the author of the server is KL。I'm a server writer myself, and I don't want someone stealing my scripts and publishing them。Instead of apologizing to KL, they repeatedly showed off the scripts they had obtained。So I had to ask the administrator to ban their server IP from the master list。