Getting started with Fork3X - VikkoMakesStuff/Fork3X GitHub Wiki

Fork3X is a powerful building utility based on another work known as F3X. It adds a lot of features that can be implemented in ease.


1. Adding Fork3X in your game


Adding Fork3X in a game is actually pretty way to go.

For the tool:

  1. Install the latest version of the Fork3X tool (Fork3XvXXX) on the GitHub repository.
  2. Open Roblox Studio.
  3. Open the place you want Fork3X to be on.
  4. Open the explorer and right click on Workspace. Choose Insert from File...
  5. Find the file you installed previously.
  6. The Fork3X are now in your game. Open them and double-click on the Options module and change the settings like you want.
  7. Go in Libraries -> CommunicationBridge -> WebhookSetup and change the webhook to your webhook if you're interested in getting noticed.

For the plugin:

  1. Install the latest version of the Fork3X plugin (Fork3XvXXXPlugin) on the GitHub repository.
  2. Open Roblox Studio.
  3. Open any place of your wish.
  4. Open the explorer and right click on Workspace. Choose Insert from File...
  5. Find the file you installed previously.
  6. Right click the building tools again and click on Save as Local Plugin...
  7. Save the file in the Plugins folder.
  8. Toggle the Fork3X building tools by clicking on the plugin's icon.

You can also insert directly the file in the Plugins folder. However, you need to have access to your AppData folder in order to do it!


2. Key elements (FOR ADVANCED USES)


The first time you might open the Fork3X's options, there might be some things you don't understand. Don't worry. Most of them are explained here:

Core

The core module is the module that's responsible of controlling the building tools. They don't contain any of the tools, but sets up the whole building tools when you open them.

The core module will trigger the following things when enabled:

a) The dock

The dock is the same of the UI you can see at the right of the screen, it is handled with Roact, another utility to create UIs without needing to use a bunch of scripts and ensure a stable communication between each script.

The dock is separated in two sections:

  1. The topbar: with the CementDark theme (the default theme), the topbar replaces the about pane and fills exactly the same role: informing the user about most essential things that they need to know about the tool.

  2. The tool list: this is where you can find every tools, this means every utilities that save their state even if closed.

  3. The selection pane: every functions that are called once or that are made to be used with other tools.

  4. The about pane: with older themes such as GigsDark, the about pane works like the topbar but is found at the very bottom.

You can edit the dock in the UI folder. Be careful! Each profile/theme has its own UI folder.

b) Hotkeys

Hotkeys concern everything that's binded to the user's actions. For example, when you press M to open the marketplace tool, you're triggering a hotkey.

If you're interested in binding hotkeys with tools, you must add them in the Loader folder that will be explained in the c) section

If you're looking to bind a hotkey to a function called from the selection pane, look in the d) section.

c) Tools

Tools are, like explained before, every utilities that save their state even if closed. If you're looking for something that isn't one-time or that gets overridden when another utility is opened, you must create a tool.

In order to add a new tool, you must:

  1. Open the Loader module.
  2. Copy this sheet of code and modify it according to your needs:
local XTool = require(CoreTools:WaitForChild 'X')
Core.AssignHotkey(KEY, Core.Support.Call(Core.EquipTool, XTool));
Core.AddToolButton(Core.Assets.XIcon, KEYTEXT, XTool, POSITION, SIZE)

Consider the following:

  • X is the name of your tool.
  • Your tool's script must be a module script located in Tools.
  • KEY is the key to which the tool is binded. KEY must be a string or a table containing multiple strings, considering that each string can be found in Enum.KeyCode
  • [X]Icon is the icon of the tool in the dock. You can directly input the asset id, or put it in the Assets module to respect DRY (Don't Repeat Yourself). Remember you can use logic gates (ISUSINGPROFILE and "rbxassetid://ID" or "rbxassetid://ID2") if you want a better control on when to use which icon.
  • KEYTEXT is what needs to be displayed as a key in the dock. RichText is supported, so feel free to make use of it for longer texts (SHIFT+K i. e.)
  • POSITION and SIZE are some custom UDim2 value you can input to shrink/scale icons to make them fit the UI better. They are optional, and you can just not input them if you don't need them.

d) Selection buttons

The selection buttons are the buttons seen in the selection pane, the lower section of the dock. They are made for one time functions such as undo/redo or utilities that are made to be used parallely (explorer).

If you're looking to add a new button for the selection pane:

  1. Head to the UI folder of the current theme and open Dock -> SelectionPane
  2. Go down of the module and do a line break near the ; next to the last button Roact function.
  3. Copy-paste the following Roact function:
		XButton = new(SelectionButton, {
			LayoutOrder = [Previous button's LayoutOrder + 1];
			IconAssetId = ICON;
			IsActive = self.state.[YOUR STATE];
			OnActivated = self.props.Core.[FUNCTION];
			TooltipText = '<b>[NAME]</b><br />[KEYTEXT]';
			Size = UDim2.new(0.7, 0, 0.7, 0); -- Optional
			Position = UDim2.new(0.175, 0, 0.15, 0); -- Optional
		});

Consider the following:

  • ICON is the asset ID of your Selection Button's icon.
  • YOUR STATE is a value that will update the button when used. You can add state signals from the Options module in the CoreCustomConnections function, which is used to add connections and variables that don't need to be binded. Example:
local Signal = require(Tool.Libraries.Signal)
Core.IsTesting = Signal.new()

And in the :init() function:

	self:Testing([[FUNCTION THAT UPDATES THE STATE WITH self:SetState({ Testing = true })]])
	self.Maid.TrackTesting = self.props.Core.IsTesting:Connect(function ()
		self:Testing([[FUNCTION THAT UPDATES THE STATE WITH self:SetState({ Testing = true })]])
	end)
  • FUNCTION which is the function you add via the CoreCustomFunctions setting in the Options module. To set it up, you must add this in the table:
FUNCTIONNAME = {function() print("Hello world!") end, KEY}
  • NAME which is the utility's name.
  • KEYNAME which is what's written under the selection button when hovered.

SyncAPI and SyncModule

Respectively a BindableFunction (instance you can fire to trigger a function that return something) and a ModuleScript, those are essential in replicating things from the client to the server. The module contains the functions that will perform the action in the server. That means that the tool will invoke SyncAPI to trigger the function in SyncModule that's responsible to replicate.

To add functions in the SyncModule, you can add your function in the SyncAPIExtraFunctions setting in the Options module like here:

	['FUNCTION'] = function (Player, Security, TheArgumentsYouMentionedWhenInvokingSyncAPI)
		print("foo")
	end;

Tools

The tools are the most important things in the Building Tools. They allow the user to perform most actions.

When creating your tool, make sure of the following:

  • It must have a EquipTool() function and a UnequipTool() function.
  • It should update History when applying changes. History records are tables that are sent to another module so the user can revert actions they did. They are structured so:
local Core = require(Tool.Core)

function TrackChange(foo)

	-- Start the record
	HistoryRecord = {
		Selection = Selection.Items;
		-- INSERT EVERYTHING YOU NEED SUCH AS POSITIONS, BEFORE PROPERTIES, AFTER PROPERTIES, ETC...


		Unapply = function (Record)
			-- Reverts this change

			-- Select the changed parts
			Selection.Replace(Record.Selection)

			`-- Send the change request`
			Core.SyncAPI:Invoke('FUNCTION', Record["WHATYOUNEED"]);

		end;

		Apply = function (Record)
			-- Applies this change

			-- Select the changed parts
			Selection.Replace(Record.Selection)

			-- Send the change request
			Core.SyncAPI:Invoke('FUNCTION', Record["WHATYOUNEED"]);

		end;

	};

end;

function Foo(bar)
	-- DO EVERYTHING
	TrackChange(bar)
	-- CHANGE THE HISTORY RECORD WITH HistoryRecord["EXAMPLE"] IF NEEDED
	Core.SyncAPI:Invoke('FUNCTION', Record["WHATYOUNEED"]);
	Core.History.Add(HistoryRecord);
end;
⚠️ **GitHub.com Fallback** ⚠️