Jump to content

Recommended Posts

Hi

I want to create an easy utility / library resource where I would store functions that is used often but not provided in MTA by default. This resource, called Lib looks like this:

Lib/
	G_Libs.lua
	meta.xml
	libs/
		C_dx.lua
		C_gui.lua
		C_screen.lua
		G_element.lua
		G_math.lua
		G_table.lua
		...

the meta.xml for the Lib resource:


<meta>
    <info author="driphunnid" type="utility" name="Libs" />

    <download_priority_group>3</download_priority_group>
    <min_mta_version client="1.6.0" server="1.6.0" />

    <!--
    <include resource="" />
    -->

    <!-- a config must be an xml file, types: client or server -->
    <!--
    <config src=".xml" type="client" />
    <config src=".xml" type="server" />
    -->

    <oop>true</oop>

    <!--
    <settings>
        <setting name="" value="" />
    </settings>
    -->

    <!--
    <aclrequest>
        <right name="function.startResource" access="true" />
        <right name="function.stopResource" access="true" />
    </aclrequest>
    -->

    <!-- Shared -->

    <script src="libs/G_number.lua" type="shared" />
    <script src="libs/G_string.lua" type="shared" />
    <script src="libs/G_table.lua" type="shared" />
    <script src="libs/G_color.lua" type="shared" />

    <script src="libs/G_math.lua" type="shared" />
    <script src="libs/G_vector.lua" type="shared" />
    <script src="libs/G_matrix.lua" type="shared" />
    <script src="libs/G_position.lua" type="shared" />
    <script src="libs/G_rotation.lua" type="shared" />

    <script src="libs/G_material.lua" type="shared" />
    <script src="libs/G_bone.lua" type="shared" />
    <script src="libs/G_weapon.lua" type="shared" />

    <script src="libs/G_world.lua" type="shared" />
    <script src="libs/G_element.lua" type="shared" />
    <script src="libs/G_vehicle.lua" type="shared" />
    
    <script src="libs/G_cfg.lua" type="shared" />
    
    <!-- Client -->

    <script src="libs/C_screen.lua" type="client" />
    <script src="libs/C_gui.lua" type="client" />
    <script src="libs/C_dx.lua" type="client" />

    <script src="libs/C_ped.lua" type="client" />
    <script src="libs/C_vehicle.lua" type="client" />


    

    <script src="G_Libs.lua" type="shared" />
    <export function="load" type="shared" />

</meta>

and the G_Libs.lua contains this simple fileReading logic - we return the content of a read file:

LIBS_FOLDER = "libs"

function load(name, side) -- side = prefix - client, server or shared / global - C, S, G
    assert(type(name) == "string", "Bad argument @'load' [Expected string at argument 1, got "..type(name).."]")
    side = type(side) == "string" and side or "G"
    local libPath = string.format("%s/%s_%s.lua", LIBS_FOLDER, side, name)
    assert(fileExists(libPath), "Library not found: " .. libPath .. " - you might need to specify a /different/ side (C, S, G).")

    local file = fileOpen(libPath)
    local content = fileRead(file, fileGetSize(file))
    fileClose(file)
    return content
end

 

For example, content of libs/G_element.lua and C_screen.lua:

C_screen.lua:

SCREEN_SIZE = Vector2(guiGetScreenSize())
MEDIAN_SCREEN_SIZE = Vector2(1440, 900)

function ssX(x)
    return x / MEDIAN_SCREEN_SIZE.x * SCREEN_SIZE.x
end

function ssY(y)
    return y / MEDIAN_SCREEN_SIZE.y * SCREEN_SIZE.y
end

function isCursorInPosition(x, y, width, height)
	if (not isCursorShowing()) then
		return false
	end
	local cx, cy = getCursorPosition()
	local cx, cy = (cx * SCREEN_SIZE.x), (cy * SCREEN_SIZE.y)
	
	return ((cx >= x and cx <= x + width) and (cy >= y and cy <= y + height))
end

function isCursorInCircle(x, y, r)
	if (not isCursorShowing()) then
		return false
	end
	local cx, cy = getCursorPosition()
	local cx, cy = cx*SCREEN_SIZE.x, cy*SCREEN_SIZE.y
	
	return (x-cx)^2+(y-cy)^2 <= r^2
end



G_element.lua:

function isPlayer(element)
	if not isElement(element) then return false end
	if not (getElementType(element) == "player") then return false end
	return true
end

function isPed(element)
	if not isElement(element) then return false end
	if not (getElementType(element) == "ped") then return false end
	return true
end

function isCharacter(element)
	if not isElement(element) then return false end
    if not (isPed(element) or isPlayer(element)) then return false end
	if not (element.model == 0) then return false end
	return true
end

function isVehicle(element)
	if not isElement(element) then return false end
	if not (getElementType(element) == "vehicle") then return false end
	return true
end

function isObject(element)
	if not isElement(element) then return false end
	if not (getElementType(element) == "object") then return false end
	return true
end

function isBuilding(element)
    if not isElement(element) then return false end
    if not (getElementType(element) == "building") then return false end
    return true
end

 

When I use loadstring with this concept, it works as far as I use loadstring inside a client side script, other than that, when I try to load a lib using loadstring in a server or global / shared script, I get an Access denied error for "loadstring" and "call".

Example - other test resource:

C_test.lua (script type in xml is "client")

loadstring(exports.Lib:load("element"))() -- loads the G_element.lua file contents from Lib/libs as expected
loadstring(exports.Lib:load("screen", "C"))() -- loads the C_screen.lua file contents from Lib/libs as expected

however if I change the script type from client to server or shared, I get an error from the test.lua:

G_test.lua / S_test.lua (script type in xml is "shared" / "server")

loadstring(exports.Lib:load("element"))() -- yields an error on resource start saying Access denied for loadstring and call

I tried this setting in the test resource xml file and allowing the request via console for the resource, but same issue, still access denied:

<aclrequest>
  <right name="function.loadstring" access="true" />
  <right name="function.call" access="true" />
</aclrequest>

Are there any workarounds or fixes for this issue? I really would like to use this concept, I've been coming into so many restriction errors lately, I feel like I can't fully do what I want and have potential for. Why does loadstring not work on shared and server side scripts, or what am I missing? This concept would make editing and using utility functions so much easier, nicer and simpler for me, I don't want to let go of this.

Also I am planning to create a framework, a boilerplate "gamemode" engine, where you have so much utility functions and systems to use, that you'll only have to worry about the final gamemode concept you will be creating, this essentially will be a free open source multiplayer gta game engine, and this Lib resource would be a huge part of it.

How can I make this work?

Thank you for your time!

Edited by Dzsozi (h03)
Link to comment
  • Moderators
2 hours ago, Dzsozi (h03) said:

Are there any workarounds or fixes for this issue?

In most cases it works by default. But in some cases you need to restart the server. I ran in to that issue myself, restarting did resolve the problem for me.

 

For the following info, I used the resource runcode as example.

 

Step 1A, check if the request is applied:

aclrequest list runcode all

image.png.e1168042704b968e4be03b9f84b42d26.png

Step 1B, if not, run:

aclrequest allow runcode all

Step 2A

Test if the error is gone.

Step 2B, not working?

Restart the server

Step 2C

Still not working?

Give the resource temporary admin rights and resolve it later.

 


btw. not to go offtopic, but a reminder that I replied on your other topic with `PointOfInterest`.

Link to comment
39 minutes ago, IIYAMA said:

btw. not to go offtopic, but a reminder that I replied on your other topic with `PointOfInterest`.

I saw it, but to be honest I couldn’t make up anything properly working so I postponded that project to rework the base of the systems and utilizations, I couldn’t figure out a way that I like and would use. So I started reworking my Lib resource to use the current concept in this topic. Thank you on that case very much, I will get back to it but I need this system finished first. Sorry if I came off rude for not replying, I didn’t mean to be.


 

I already verified that the aclrequest has been accepted previously, i did this via console commands, but I would prefer if I didn’t have to assign a new aclrequest per resource, rather to work it easily and automatically.

The server has been already restarted since the creation of this post and the issue is the same and still persists no matter if the aclrequest is there in the meta and accepted by an admin or not.

So far I only noticed this issue inside shared and server side loadstrings. Is it possible that maybe I messed up something in my acl.xml settings?

btw I didnt really use runcode before and don’t really see the point of it nor I really know what it is, like I script in/with files.

 

spacer.png

After I made these changes I restarted the server entirely by closing the console terminal, and the same issue is present:

spacer.png

 

As I said before, there's no such issue when using loadstring on client side scripts, I can manually and dynamically restart a resource and Lib resource if I change something in the Lib and it works as expected.

Edited by Dzsozi (h03)
Link to comment
  • Moderators
14 minutes ago, Dzsozi (h03) said:

Thank you on that case very much, I will get back to it but I need this system finished first

No worries take your time, just checking if you may have mist it. 👍

 

4 minutes ago, Dzsozi (h03) said:

So far I only noticed this issue inside shared and server side loadstrings.

Serverside (as well as shared~serverside) are limited by the ACL, clientside is not.

 

5 minutes ago, Dzsozi (h03) said:

Is it possible that maybe I messed up something in my acl.xml settings?

That is possible.

You can double verify if the resource has access to loadstring using: https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo

addEventHandler("onResourceStart",  resourceRoot, function (startedResource)
    if not hasObjectPermissionTo ( startedResource, "function.loadstring", true ) then
        local cancelReason = "Missing permission function.loadstring"
        outputDebugString(cancelReason, 2)
        cancelEvent(true, cancelReason) -- Something is wrong, stop startup
    end
end, false)

 

You could also make a copy of your current ACL and use the default one:

https://github.com/multitheftauto/mtasa-blue/blob/master/Server/mods/deathmatch/acl.xml

 

 

 

Link to comment

Thank you for your help, I managed to fix this issue - and probably prevented some upcoming issues - by adding the following to the ACL:

<acl>	
	<group name="ServerScript">
        <acl name="ServerScript"></acl>
        <object name="resource.*"></object>
    </group>
  	<acl name="ServerScript">
      	<right name="function.loadstring" access="true"></right>
      	...
  	</acl>
</acl>

Have a great day, thanks again @IIYAMA for your help and time!

Edited by Dzsozi (h03)
added full xml in case others need it because of this or similar problems
  • Like 1
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...