Is it possible to retrieve an object instance from a class created in one script in another script

Hello, is it possible for Script 2 (LocalScript) to access the object instance (myGun) that was created in Script 1 (Script), without storing it in a manual table or using RemoteEvents/BindableEvents? Would there be an advanced way to do this?.

Code example:

Gun Module (ModuleScript)

local gun = {}
gun.__index = gun

function gun.new(tool)
    local self = setmetatable({}, gun)
    self.gun = tool
    return self
end

function gun:init()
    print(self.gun)
end

return gun

Script 1 (Script)

local gun_module = require(script.Parent.gun_module)
local tool = workspace.tool
local myGun = gun_module.new(tool)

Script 2 (LocalScript)

local gun_module = require(script.Parent.gun_module)
local myTool = workspace.tool
-- How can I access the object that was created in Script 1 without manually storing it in a table or using Remotes/Bindables?
-- And then for example, do :init() on it

Questions if it’s possible:

  1. If the client modifies values such as self variables through methods, will these changes replicate or reflect for the other clients, and the server?

  2. If the client changes values (like self variables) through methods, and then the server changes them with different values, will the client’s changes be overridden by the server’s update?

Any solution will be appreciated, thanks.

1 Like

One thing i learned recently is you can make a module that stores these requires

-- SharedGunModule.lua (Replicated Storage?)

return {
 myGun = require(path.to.gun_module)
 anotherGun = require(path.to.another_gun)
}

Then you can reference it where you need it. Example:

-- Server Script ?
local SharedGunModule = require(path.to.SharedGunModule)
local myGun = SharedGunModule.myGun

myGun:Init()

Same thing but with the client now… Example:

-- Client ( Starter Player Scripts ? )
local SharedGunModule = require(path.to.SharedGunModule)
local myGun = SharedGunModule.myGun

myGun:MuzzleEffect()

I should note that if you want to prevent exploiting (Bullet Manipulation?) you can check in the function using RunService:IsServer(). Note that it is still exploitable but it would require someone who knows what they are doing vs a copy and paste exploiter. You could also split the module into ServerStorage and ReplicatedStorage

  • ReplicatedStorage stores effects and maybe some server stuff depending on what you need
  • ServerStorage handles bullets, ammo size, a bunch of cool stuff with your gun.

Edit: You can also insert into the table of requires
table.insert(SharedGunModule, explosiveGun) i think should work, if not you may have to use
table.insert(SharedGunModule.Guns, explosiveGun)… Could test it and see if that works.

If you need me to clarify some more on some things you don’t understand just let me know!

Side Note: I know you mentioned about not using manual tables, ,but this way is efficient in my eyes. You could use an ID system for your game and set it as an attribute under the gun name thinking about it now and get the exact ID

2 Likes

If I want to add different types of guns into the same module, how should the concept and workflow be handled?

Example:

  • Script 1 (Server - ServerScriptService) adds a new gun to a player and inserts it into an OOP instance (e.g., creating a new object from GunModule).

  • Script 2 (Client - StarterPlayerScripts) checks whether the gun has been added to the player’s backpack by the server. If it exists, the client wants to fully access the same object (the exact OOP instance) and be able to call its methods like :Fire(), :Init(), or :Reload()—even if certain methods only have effect when called from the server (using RunService:IsServer()).

Sorry for my lack of understanding and if my question is confusing.

You can add them by doing what you said maybe you can convert them to use tables like this

local SharedGunModule = {}

SharedGunModule.Guns = {
	--[[Template = {
		Name = "None",
		Ammo = 5,
		Damage = 15,
	},]]--
	-- Using that template an example would be
	
	Pistol = { -- Developer Reference
		Name = "Handy Dandy Pistol", -- Display Name To User
		Ammo = 5,
		Damage = 15,
		Module = require(path.to.Pistol)
	},
}

return SharedGunModule

-- Other Script
local PistolData = SharedGunModule.Guns.Pistol
local newWeaponData = {
	Rifle = {
		Name = "Rifle",
		Ammo = 5,
		Damage = 15,
		Module = require(path.To.Rifle)
	}
}

-- Could make this into a function under SharedGunModule
-- SharedGunModule.AddData(weaponData)
for index, value in newWeaponData do
	SharedGunModule.Guns[index] = value
end

Is this what you are asking? Sorry i might not understand what you are asking

To your question, no, you cannot. This is because functions cannot be sent between the server and client, as well as other limitations of RemoteEvents as documented here. I recommend only having the object on the server.

Also, the method @McGamerNick mentioned does not work because the server and client keep separate copies of the module script in ReplicatedStorage.

There is no way to do this. The server and client are two separate environments that have to go through a translation layer to communicate across each other. You cannot create a metatable class in the server and access its methods through the client because metatables aren’t sent through the client-server boundary.

It’s common practice for games to only have the reference to the roblox instance across that boundary, but any added logic is constructed locally in each environment.

I recommend giving this a read:

Ah didn’t know that thank you for pointing that out.
If you want to pursue that way i said above just fire a remote to clone the table to the client. Or just switch to what i believe is Functional Programming as @arbitiu linked to above.

It’s actually more akin to DOD (Data Oriented Design) :point_up: :nerd_face:

in functional programming there is no mutable state

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.