Here’s a sample output of the platformer game template:
(I couldn’t include all directories due to the forum character limit)
================================================================
Repopack FOR ROBLOX - CODEBASE SNAPSHOT
Generated on: 2025-03-20 at 17:13:27
================================================================
================================================================
FILE SUMMARY
================================================================
Purpose:
--------
This file contains a packed representation of all scripts in the Roblox game.
It is designed to be easily consumable by AI systems for analysis, code review,
or other automated processes.
Codebase Statistics:
------------------
Total Scripts: 13
Script Types:
- Server Scripts: 5
- Local Scripts: 0
- Module Scripts: 8
Total Lines of Code: 644
Total Characters: 22333
Largest Script: ServerScriptService/Gameplay/Scripts/MovingPlatformController (130 lines)
File Format:
------------
The content is organized as follows:
1. This summary section
2. Directory structure
3. Multiple script entries, each consisting of:
a. A separator line (================)
b. The script path and type
c. Another separator line
d. The full contents of the script (with line numbers)
e. A blank line
Generated by:
-------------
Repopack for Roblox - A Roblox Studio plugin
================================================================
DIRECTORY STRUCTURE
================================================================
📁 ServerScriptService
📁 Gameplay
📁 Scripts
⚙️ CoinsScript
📁 MovingPlatformController
📦 getCheckpoints
📦 getPlatform
📦 visualizeCheckpointPath
⚙️ MovingPlatformsScript
⚙️ OneWayPlatformsScript
📁 Platformer
📁 Scripts
📁 Replication
📦 validateAction
📦 README
📁 Utility
📁 TypeValidation
📦 validateInstance
📦 validateString
📁 StarterPlayer
📁 StarterCharacterScripts
⚙️ CharacterLeanScript
================================================================
SCRIPTS
================================================================
================
Script: ServerScriptService/Gameplay/Scripts/CoinsScript (Script)
================
1 | --[[
2 | CoinsScript - This script implements the coin pickup system. Leaderstats are used to keep track of
3 | the amount of coins each player has. Clients detect pickups locally for minimal latency, so this script
4 | does validation to ensure they are only able to pick up nearby coins.
5 | --]]
6 |
7 | local Players = game:GetService("Players")
8 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
9 | local ServerScriptService = game:GetService("ServerScriptService")
10 |
11 | local Constants = require(ReplicatedStorage.Gameplay.Constants)
12 | local validateInstance = require(ServerScriptService.Utility.TypeValidation.validateInstance)
13 |
14 | local remotes = ReplicatedStorage.Gameplay.Remotes
15 | local pickupCoinRemote = remotes.PickupCoin
16 |
17 | local MAX_PICKUP_DISTANCE = 50
18 |
19 | local playerCoins = {}
20 |
21 | local function onPlayerAdded(player: Player)
22 | local leaderstats = Instance.new("Folder")
23 | leaderstats.Name = "leaderstats"
24 | leaderstats.Parent = player
25 |
26 | local coins = Instance.new("IntValue")
27 | coins.Name = "Coins"
28 | coins.Parent = leaderstats
29 | end
30 |
31 | local function onPlayerRemoving(player: Player)
32 | -- Clean up references so we don't leak memory
33 | if playerCoins[player] then
34 | playerCoins[player] = nil
35 | end
36 | end
37 |
38 | local function onPickupCoinFunction(player: Player, coin: BasePart): boolean
39 | -- Validate the argument being passed
40 | if not validateInstance(coin, "BasePart") then
41 | return false
42 | end
43 |
44 | -- Make sure the player is actually trying to pick up a coin
45 | if not coin:HasTag(Constants.COIN_TAG) then
46 | return false
47 | end
48 |
49 | -- Make sure the player hasn't already picked up this coin
50 | if not playerCoins[player] then
51 | playerCoins[player] = {}
52 | end
53 | if playerCoins[player][coin] then
54 | return false
55 | end
56 |
57 | -- Make sure the character is within a reasonable distance from the coin
58 | local character = player.Character
59 | if not character then
60 | return false
61 | end
62 | local distance = (character:GetPivot().Position - coin.Position).Magnitude
63 | if distance > MAX_PICKUP_DISTANCE then
64 | return false
65 | end
66 |
67 | -- Increment the player's Coins leaderstats
68 | local leaderstats = player:FindFirstChild("leaderstats")
69 | if not leaderstats then
70 | return false
71 | end
72 | local coins = leaderstats:FindFirstChild("Coins")
73 | if not coins then
74 | return false
75 | end
76 | coins.Value += 1
77 |
78 | -- Save this coin as picked up so the player can't pick it up multiple times
79 | -- This is stored per player since we want multiple players to be able to pick up each coin
80 | playerCoins[player][coin] = true
81 |
82 | -- Return true so the client knows it successfully picked up the coin
83 | return true
84 | end
85 |
86 | local function initialize()
87 | Players.PlayerAdded:Connect(onPlayerAdded)
88 | Players.PlayerRemoving:Connect(onPlayerRemoving)
89 |
90 | pickupCoinRemote.OnServerInvoke = onPickupCoinFunction
91 | end
92 |
93 | initialize()
94 |
================
Script: ServerScriptService/Gameplay/Scripts/MovingPlatformController (ModuleScript)
================
1 | --[[
2 | MovingPlatformController - This module script implements a class for moving platforms.
3 |
4 | AlignPosition and AlignOrientation are used to move the platform between each checkpoint.
5 | Beams are created to visual the path that the platform will take.
6 | --]]
7 |
8 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
9 |
10 | local Constants = require(ReplicatedStorage.Gameplay.Constants)
11 | local disconnectAndClear = require(ReplicatedStorage.Utility.disconnectAndClear)
12 | local getCheckpoints = require(script.getCheckpoints)
13 | local getPlatform = require(script.getPlatform)
14 | local visualizeCheckpointPath = require(script.visualizeCheckpointPath)
15 |
16 | local MovingPlatformController = {}
17 | MovingPlatformController.__index = MovingPlatformController
18 |
19 | function MovingPlatformController.new(platformContainer: Instance)
20 | local platform = getPlatform(platformContainer)
21 | local checkpoints = getCheckpoints(platformContainer)
22 |
23 | local speed = platformContainer:GetAttribute(Constants.MOVING_PLATFORM_SPEED_ATTRIBUTE)
24 | local angularSpeed = platformContainer:GetAttribute(Constants.MOVING_PLATFORM_ANGULAR_SPEED_ATTRIBUTE)
25 |
26 | local attachment = Instance.new("Attachment")
27 | attachment.Name = "MovingPlatformAttachment"
28 | attachment.Parent = platform
29 |
30 | -- Create an AlignPosition to use for moving the platform around
31 | local alignPosition = Instance.new("AlignPosition")
32 | alignPosition.Mode = Enum.PositionAlignmentMode.OneAttachment
33 | alignPosition.Attachment0 = attachment
34 | alignPosition.MaxForce = math.huge
35 | alignPosition.MaxVelocity = speed
36 | alignPosition.Responsiveness = Constants.MOVING_PLATFORM_RESPONSIVENESS
37 | alignPosition.Parent = platform
38 |
39 | -- Create an AlignOrientation to use for rotating the platform
40 | local alignOrientation = Instance.new("AlignOrientation")
41 | alignOrientation.Mode = Enum.OrientationAlignmentMode.OneAttachment
42 | alignOrientation.Attachment0 = attachment
43 | alignOrientation.MaxTorque = math.huge
44 | alignOrientation.MaxAngularVelocity = angularSpeed
45 | alignOrientation.Responsiveness = Constants.MOVING_PLATFORM_RESPONSIVENESS
46 | alignOrientation.Parent = platform
47 |
48 | local self = {
49 | platformContainer = platformContainer,
50 | checkpointIndex = 1,
51 | platform = platform,
52 | alignPosition = alignPosition,
53 | alignOrientation = alignOrientation,
54 | checkpoints = checkpoints,
55 | connections = {},
56 | }
57 | setmetatable(self, MovingPlatformController)
58 | self:initialize()
59 | return self
60 | end
61 |
62 | function MovingPlatformController:initialize()
63 | -- Update the constraints when the attributes are changed
64 | table.insert(
65 | self.connections,
66 | self.platformContainer:GetAttributeChangedSignal(Constants.MOVING_PLATFORM_SPEED_ATTRIBUTE):Connect(function()
67 | local speed = self.platformContainer:GetAttribute(Constants.MOVING_PLATFORM_SPEED_ATTRIBUTE)
68 | self.alignPosition.MaxVelocity = speed
69 | end)
70 | )
71 |
72 | table.insert(
73 | self.connections,
74 | self.platformContainer
75 | :GetAttributeChangedSignal(Constants.MOVING_PLATFORM_ANGULAR_SPEED_ATTRIBUTE)
76 | :Connect(function()
77 | local angularSpeed =
78 | self.platformContainer:GetAttribute(Constants.MOVING_PLATFORM_ANGULAR_SPEED_ATTRIBUTE)
79 | self.alignOrientation.MaxAngularVelocity = angularSpeed
80 | end)
81 | )
82 |
83 | -- Visualize the path the platform will take
84 | visualizeCheckpointPath(self.checkpoints)
85 |
86 | -- Move the platform to the first checkpoint
87 | local checkpoint = self.checkpoints[self.checkpointIndex]
88 | self.platform.CFrame = checkpoint.CFrame
89 | self.alignPosition.Position = checkpoint.Position
90 | self.alignOrientation.CFrame = checkpoint.CFrame
91 | end
92 |
93 | function MovingPlatformController:move()
94 | -- Find the next checkpoint, looping back to the first once we reach the end
95 | local nextCheckpointIndex = self.checkpointIndex + 1
96 | if nextCheckpointIndex > #self.checkpoints then
97 | nextCheckpointIndex = 1
98 | end
99 | self.checkpointIndex = nextCheckpointIndex
100 |
101 | -- Calculate the time needed to reach the next checkpoint
102 | local checkpoint = self.checkpoints[nextCheckpointIndex]
103 | local distance = (self.platform.Position - checkpoint.Position).Magnitude
104 | local timeToNextCheckpoint = distance / self.alignPosition.MaxVelocity
105 |
106 | -- Move to the next checkpoint
107 | self.alignPosition.Position = checkpoint.Position
108 | self.alignOrientation.CFrame = checkpoint.CFrame
109 |
110 | -- Wait for the time it takes to reach the checkpoint + the delay at each checkpoint before moving on
111 | -- We'll save this task so we can cancel it later if we need to stop the checkpoint moving
112 | local delayTime = self.platformContainer:GetAttribute(Constants.MOVING_PLATFORM_DELAY_ATTRIBUTE)
113 | self.moveTask = task.delay(timeToNextCheckpoint + delayTime, self.move, self)
114 | end
115 |
116 | function MovingPlatformController:stop()
117 | -- If we have a current move task, cancel it so it doesn't loop forever
118 | if self.moveTask then
119 | task.cancel(self.moveTask)
120 | self.moveTask = nil
121 | end
122 | end
123 |
124 | function MovingPlatformController:destroy()
125 | self:stop()
126 | disconnectAndClear(self.connections)
127 | end
128 |
129 | return MovingPlatformController
130 |
================
Script: ServerScriptService/Gameplay/Scripts/MovingPlatformController/getCheckpoints (ModuleScript)
================
1 | --[[
2 | getCheckpoints - A utility function to get all the checkpoints for a moving platform and
3 | ensure they are all in order.
4 | --]]
5 |
6 | local function getCheckpoints(platformContainer: Instance): { BasePart }
7 | local checkpointsFolder = platformContainer:FindFirstChild("Checkpoints")
8 | assert(checkpointsFolder, `No Checkpoints in {platformContainer:GetFullName()}`)
9 |
10 | -- Make sure all the checkpoints exist
11 | local checkpoints = {}
12 | local numCheckpoints = #checkpointsFolder:GetChildren()
13 | for i = 1, numCheckpoints do
14 | local checkpoint = checkpointsFolder:FindFirstChild(`Checkpoint{i}`)
15 | assert(checkpoint, `{platformContainer:GetFullName()} missing checkpoint: Checkpoint{i}`)
16 | table.insert(checkpoints, checkpoint)
17 | end
18 |
19 | return checkpoints
20 | end
21 |
22 | return getCheckpoints
23 |
================
Script: ServerScriptService/Gameplay/Scripts/MovingPlatformController/getPlatform (ModuleScript)
================
1 | --[[
2 | getPlatform - A utility function to get the main platform being used for a moving platform.
3 | --]]
4 |
5 | local function getPlatform(platformContainer: Instance): BasePart
6 | local platform = platformContainer:FindFirstChild("Platform")
7 | assert(platform, `No Platform in {platformContainer:GetFullName()}`)
8 |
9 | return platform
10 | end
11 |
12 | return getPlatform
13 |
================
Script: ServerScriptService/Gameplay/Scripts/MovingPlatformController/visualizeCheckpointPath (ModuleScript)
================
1 | --[[
2 | visualizeCheckpointPath - A utility function to create beams in between the checkpoints for a moving platform.
3 | --]]
4 |
5 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
6 |
7 | local getOrCreateAttachment = require(ReplicatedStorage.Utility.getOrCreateAttachment)
8 |
9 | local beamTemplate = ReplicatedStorage.Gameplay.Objects.PlatformPathBeam
10 |
11 | local function visualizeCheckpointPath(checkpoints: { BasePart })
12 | for index, checkpoint in checkpoints do
13 | checkpoint.Transparency = 1
14 |
15 | if #checkpoints == 2 and index == 2 then
16 | -- If there are only two checkpoints, no need to create a second beam back from Checkpoint2 to Checkpoint1
17 | return
18 | end
19 |
20 | -- Create a beam between the two checkpoints
21 | local nextCheckpoint = checkpoints[index + 1] or checkpoints[1]
22 | local checkpointAttachment = getOrCreateAttachment(checkpoint, "PlatformPathAttachment")
23 | local nextCheckpointAttachment = getOrCreateAttachment(nextCheckpoint, "PlatformPathAttachment")
24 |
25 | local beam = beamTemplate:Clone()
26 | beam.Attachment0 = checkpointAttachment
27 | beam.Attachment1 = nextCheckpointAttachment
28 | beam.Parent = checkpoint
29 | end
30 | end
31 |
32 | return visualizeCheckpointPath
33 |
================
Script: ServerScriptService/Gameplay/Scripts/MovingPlatformsScript (Script)
================
1 | --[[
2 | MovingPlatformsScript - This script creates and destroys MovingPlatformController classes as necessary for any
3 | instances tagged with Constants.MOVING_PLATFORM_TAG.
4 | --]]
5 |
6 | local CollectionService = game:GetService("CollectionService")
7 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
8 |
9 | local Constants = require(ReplicatedStorage.Gameplay.Constants)
10 | local MovingPlatformController = require(script.Parent.MovingPlatformController)
11 |
12 | local movingPlatformControllers = {}
13 |
14 | local function onMovingPlatformAdded(platform: Instance)
15 | if movingPlatformControllers[platform] then
16 | return
17 | end
18 |
19 | local controller = MovingPlatformController.new(platform)
20 | movingPlatformControllers[platform] = controller
21 |
22 | controller:move()
23 | end
24 |
25 | local function onMovingPlatformRemoved(platform: Instance)
26 | if movingPlatformControllers[platform] then
27 | movingPlatformControllers[platform]:destroy()
28 | movingPlatformControllers[platform] = nil
29 | end
30 | end
31 |
32 | local function initialize()
33 | CollectionService:GetInstanceAddedSignal(Constants.MOVING_PLATFORM_TAG):Connect(onMovingPlatformAdded)
34 | CollectionService:GetInstanceRemovedSignal(Constants.MOVING_PLATFORM_TAG):Connect(onMovingPlatformRemoved)
35 |
36 | for _, platform in CollectionService:GetTagged(Constants.MOVING_PLATFORM_TAG) do
37 | onMovingPlatformAdded(platform)
38 | end
39 | end
40 |
41 | initialize()
42 |
================
Script: ServerScriptService/Gameplay/Scripts/OneWayPlatformsScript (Script)
================
1 | --[[
2 | OneWayPlatformsScript - This script sets up the collision groups for one way platforms. This is
3 | necessary to avoid issues with moving platforms and distributed physics simulation.
4 |
5 | For example: If a player is above a platform (i.e. CanCollide = true) and has simulation ownership of it,
6 | its movement will be affected since the client sees it as collidable. This can lead to cases where the
7 | platform will run into other characters and glitch out.
8 |
9 | To fix this, we assign the platforms and characters to collision groups which do not collide with each other.
10 | Each player locally assigns their character back to a collision group which does collide with the platforms.
11 | This allows the client to simulate collisions with its own character but not with other characters.
12 | --]]
13 |
14 | local CollectionService = game:GetService("CollectionService")
15 | local PhysicsService = game:GetService("PhysicsService")
16 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
17 |
18 | local Constants = require(ReplicatedStorage.Gameplay.Constants)
19 | local safePlayerAdded = require(ReplicatedStorage.Utility.safePlayerAdded)
20 |
21 | local function onCharacterAdded(character: Model)
22 | character.DescendantAdded:Connect(function(descendant: Instance)
23 | if descendant:IsA("BasePart") then
24 | descendant.CollisionGroup = Constants.CHARACTER_GROUP
25 | end
26 | end)
27 |
28 | for _, descendant in character:GetDescendants() do
29 | if descendant:IsA("BasePart") then
30 | descendant.CollisionGroup = Constants.CHARACTER_GROUP
31 | end
32 | end
33 | end
34 |
35 | local function onPlayerAdded(player: Player)
36 | player.CharacterAdded:Connect(onCharacterAdded)
37 |
38 | if player.Character then
39 | onCharacterAdded(player.Character)
40 | end
41 | end
42 |
43 | local function onPlatformAdded(platform: Instance)
44 | assert(platform:IsA("BasePart"), `{platform} should be a BasePart`)
45 |
46 | platform.CollisionGroup = Constants.ONE_WAY_PLATFORM_GROUP
47 | end
48 |
49 | local function initializeCollisionGroups()
50 | PhysicsService:RegisterCollisionGroup(Constants.CHARACTER_GROUP)
51 | PhysicsService:RegisterCollisionGroup(Constants.LOCAL_CHARACTER_GROUP)
52 | PhysicsService:RegisterCollisionGroup(Constants.ONE_WAY_PLATFORM_GROUP)
53 |
54 | PhysicsService:CollisionGroupSetCollidable(Constants.CHARACTER_GROUP, Constants.ONE_WAY_PLATFORM_GROUP, false)
55 | end
56 |
57 | local function initialize()
58 | initializeCollisionGroups()
59 |
60 | CollectionService:GetInstanceAddedSignal(Constants.ONE_WAY_PLATFORM_TAG):Connect(onPlatformAdded)
61 | safePlayerAdded(onPlayerAdded)
62 |
63 | for _, platform in CollectionService:GetTagged(Constants.ONE_WAY_PLATFORM_TAG) do
64 | onPlatformAdded(platform)
65 | end
66 | end
67 |
68 | initialize()
69 |
================
Script: ServerScriptService/Platformer/Scripts/Replication (Script)
================
1 | --[[
2 | Replication - This script handles the replication of platforming actions that players are doing.
3 | Actions are validated and then replicated using an attribute on the character model.
4 | --]]
5 |
6 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
7 | local ServerScriptService = game:GetService("ServerScriptService")
8 |
9 | local Constants = require(ReplicatedStorage.Platformer.Constants)
10 | local validateString = require(ServerScriptService.Utility.TypeValidation.validateString)
11 | local validateAction = require(script.validateAction)
12 |
13 | local remotes = ReplicatedStorage.Platformer.Remotes
14 | local setActionRemote = remotes.SetAction
15 |
16 | local function onSetActionEvent(player: Player, action: string)
17 | -- Validate arguments
18 | if not validateString(action) then
19 | return
20 | end
21 |
22 | -- Make sure the player has a character
23 | local character = player.Character
24 | if not character then
25 | return
26 | end
27 |
28 | -- Make sure this is a valid action
29 | if not validateAction(action) then
30 | return
31 | end
32 |
33 | -- Since the client is already setting ACTION_ATTRIBUTE, we have the server set a separate REPLICATED_ACTION_ATTRIBUTE.
34 | -- This avoids issues where a client with poor connection could have the attribute overwritten by the server.
35 | character:SetAttribute(Constants.REPLICATED_ACTION_ATTRIBUTE, action)
36 | end
37 |
38 | setActionRemote.OnServerEvent:Connect(onSetActionEvent)
39 |
================
Script: ServerScriptService/Platformer/Scripts/Replication/validateAction (ModuleScript)
================
1 | --[[
2 | validateAction - A utility function to check if an action is actually valid to do.
3 | This is done by checking for the existence of action modules stored in ReplicatedStorage.Platformer.Scripts.Actions.
4 |
5 | Since using FindFirstChild can be expensive and this function will be called frequently by players,
6 | we opt to cache the list of valid actions.
7 | --]]
8 |
9 | local ReplicatedStorage = game:GetService("ReplicatedStorage")
10 |
11 | local actions = ReplicatedStorage.Platformer.Scripts.Actions
12 |
13 | local validActions = {
14 | None = true,
15 | }
16 |
17 | for _, action in actions:GetChildren() do
18 | validActions[action.Name] = true
19 | end
20 |
21 | local function validateAction(action: string): boolean
22 | return validActions[action] or false
23 | end
24 |
25 | return validateAction
26 |
================
Script: ServerScriptService/README (ModuleScript)
================
1 | --[[
2 | # Platformer Template
3 |
4 | ## Overview
5 |
6 | This platformer template serves as a demonstration of basic platforming mechanics
7 | and coin collection mechanics. Players can jump and double jump, roll and dash
8 | (shift on keyboard, X/square on gamepad), and long jump by jumping right after
9 | initiating a roll.
10 |
11 | ## Project Structure
12 |
13 | Client scripts and objects are stored in ReplicatedStorage, the scripts have their
14 | RunContext set to Client so they do not need to be parented to PlayerScripts.
15 |
16 | Server scripts and objects are stored in ServerScriptService.
17 |
18 | The same structure is used for both server and client - instances and scripts are
19 | broken up into three different categories:
20 |
21 | * Platformer
22 | * Gameplay
23 | * Utility
24 |
25 | ### Platformer
26 |
27 | The Platformer folder contains instances and scripts specifically related to the
28 | platforming abilities. This includes the main control script, remote events for
29 | replication, effects and effect scripts, and more.
30 |
31 | A Constants module is included here to provide a central place to modify all
32 | Platformer-related constants.
33 |
34 | ### Gameplay
35 |
36 | The Gameplay folder contains instances and scripts related to supplementary
37 | gameplay elements, such as moving platforms, coin pickups, etc.
38 |
39 | A second Constants module is included here to provide a central place to modify
40 | all Gameplay-related constants.
41 |
42 | ### Utility
43 |
44 | The Utility folder contains utility functions and libraries that are used by
45 | various systems throughout the template.
46 |
47 | ## Character Controller
48 |
49 | The Controller class (found in `ReplicatedStorage.Platformer.Scripts.Controller`)
50 | contains the main control code for the character. This includes movement, momentum,
51 | and initiating various actions.
52 |
53 | In order to easily support multiple input types without forking or re-implementing
54 | the default control scripts, movement and jump input is read from the local character's
55 | humanoid in a RenderStep loop and then written back to it by the Controller. This is
56 | done inside `ReplicatedStorage.Platformer.Scripts.ControlScript`.
57 |
58 | ## Actions
59 |
60 | Actions are the various platforming moves that a character can make, such as rolling
61 | or double jumping. These are all stored as modules in `ReplicatedStorage.Platformer.Scripts.Actions`.
62 |
63 | Each action can specify animations, effects, and sounds to play when it is initiated,
64 | as well as the acceleration the character should have during the action and whether
65 | it should be automatically ended when the character lands on the ground.
66 |
67 | * minTimeInAction - Used when clearOnGrounded = true, prevents the action from being stopped
68 | immediately if initiated on the ground
69 | * clearOnGrounded - When set the true, the controller will automatically change the action back
70 | to "None" when grounded/climbing/swimming
71 | * movementAcceleration - The acceleration to use while this is the current action
72 | * animation - The animation to play when the action begins
73 | * effect - The effect to run when the action begins
74 | * sound - The sound to play when the action begins
75 |
76 | The code for each action is inside the `Action.perform()` function, which is called
77 | when the character attempts to initiate that action. The current character Controller
78 | object is passed into this function so that actions can read values from the controller
79 | and initiate other actions if necessary.
80 |
81 | ## Coin Pickups
82 |
83 | Coin pickups are represented as a single part, which gets visually replaced on the
84 | clients by a nicer looking model. Multiple players can pick up the same coin, but only one time each.
85 |
86 | Touched events are listened to locally, which allows the client to immediately show
87 | a visual indicator that the coin has been picked up. The server does validation to
88 | make sure the client can't pick up any coin they want from anywhere on the map or pick
89 | up the same coin multiple times and then increments their leaderstats.
90 | --]]
91 |
================
Script: ServerScriptService/Utility/TypeValidation/validateInstance (ModuleScript)
================
1 | --[[
2 | validateInstance - Ensures the instance is not an 'imposter' and is of the expected class.
3 |
4 | In cases where the server is expecting an instance, exploiters can pass a table with keys
5 | that mimic the instance's properties but set to whatever they want.
6 |
7 | e.g.
8 | local fakePart = {
9 | Position = Vector3.new()
10 | }
11 |
12 | remoteExpectingPart:FireServer(fakePart)
13 |
14 | It is unsafe for the server to blindly accept the position of this fake part without
15 | checking it is a valid instance first.
16 | ]]
17 |
18 | local function validateInstance(instance: Instance, expectedClass: string): boolean
19 | if typeof(instance) ~= "Instance" then
20 | return false
21 | end
22 |
23 | return instance:IsA(expectedClass)
24 | end
25 |
26 | return validateInstance
27 |
================
Script: ServerScriptService/Utility/TypeValidation/validateString (ModuleScript)
================
1 | --[[
2 | validateString - Ensures that the passed argument is actually a string
3 | --]]
4 |
5 | local function validateString(str: string): boolean
6 | -- Make sure this is actually a string
7 | return typeof(str) == "string"
8 | end
9 |
10 | return validateString
11 |
================
Script: StarterPlayer/StarterCharacterScripts/CharacterLeanScript (Script)
================
1 | --[[
2 | CharacterLeanScript - This script makes characters slightly lean in the direction they are moving.
3 |
4 | Each Step the character's Root joint Transform is updated based on the character's velocity.
5 | --]]
6 |
7 | local RunService = game:GetService("RunService")
8 | local StarterPlayer = game:GetService("StarterPlayer")
9 |
10 | -- Since this script has RunContext of Client, it will run anywhere regardless of its parent.
11 | -- We only want it to run when it's parented to a character so we'll return immediately if it's in StarterCharacterScripts.
12 | if script.Parent == StarterPlayer.StarterCharacterScripts then
13 | return
14 | end
15 |
16 | local character = script.Parent
17 | -- Characters are not replicated atomically so we need to wait for children
18 | local humanoid = character:WaitForChild("Humanoid")
19 | local root = character:WaitForChild("HumanoidRootPart")
20 | local rootJoint = character:WaitForChild("LowerTorso"):WaitForChild("Root")
21 |
22 | local ROLL_ANGLE = math.rad(15)
23 | local PITCH_ANGLE = math.rad(5)
24 | local LEAN_SPEED = 10
25 |
26 | local leanCFrame = CFrame.new()
27 |
28 | local function onStepped(_: number, deltaTime: number)
29 | local moveVelocity = humanoid:GetMoveVelocity()
30 | local relativeVelocity = root.CFrame:VectorToObjectSpace(moveVelocity)
31 |
32 | -- Calculate pitch and roll based on the character's relative velocity
33 | local pitch = 0
34 | local roll = 0
35 | if humanoid.WalkSpeed ~= 0 then
36 | pitch = math.clamp(relativeVelocity.Z / humanoid.WalkSpeed, -1, 1) * PITCH_ANGLE
37 | roll = -math.clamp(relativeVelocity.X / humanoid.WalkSpeed, -1, 1) * ROLL_ANGLE
38 | end
39 |
40 | leanCFrame = leanCFrame:Lerp(CFrame.Angles(pitch, 0, roll), math.min(deltaTime * LEAN_SPEED, 1))
41 | -- Apply the leaning to the rootJoint's Transform
42 | rootJoint.Transform = leanCFrame * rootJoint.Transform
43 | end
44 |
45 | RunService.Stepped:Connect(onStepped)
46 |
================================================================
END OF CODEBASE
================================================================
Like Vanni said, I’ve tried to match the output of Repomix as closely as possible.