@rbxts/touch-button 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # TouchButton
2
+
3
+ ## Install
4
+ Install with [wally](https://wally.run/):\
5
+ `TouchButton = "shouxtech/touch-button@1.0.11"`
package/package.json CHANGED
@@ -1,38 +1,24 @@
1
1
  {
2
2
  "name": "@rbxts/touch-button",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "",
5
- "main": "out/init.lua",
6
- "scripts": {
7
- "build": "rbxtsc",
8
- "watch": "rbxtsc -w",
9
- "prepublishOnly": "npm run build"
10
- },
5
+ "main": "src/init.lua",
6
+ "scripts": {},
11
7
  "keywords": [],
12
8
  "author": "CriShoux",
13
9
  "license": "ISC",
14
10
  "type": "commonjs",
15
- "types": "out/index.d.ts",
11
+ "types": "src/index.d.ts",
16
12
  "files": [
17
- "out",
18
- "!**/*.tsbuildinfo"
13
+ "src"
19
14
  ],
20
15
  "publishConfig": {
21
16
  "access": "public"
22
17
  },
23
18
  "devDependencies": {
24
19
  "@rbxts/compiler-types": "^3.0.0-types.0",
25
- "@rbxts/types": "^1.0.848",
20
+ "@rbxts/types": "^1.0.896",
26
21
  "roblox-ts": "^3.0.0",
27
- "typescript": "^5.8.3"
28
- },
29
- "dependencies": {
30
- "@rbxts/charm": "^0.10.0",
31
- "@rbxts/remo": "^1.5.1",
32
- "@rbxts/roblox-observers": "^1.0.10",
33
- "@rbxts/services": "^1.5.5",
34
- "@rbxts/sleitnick-signal": "^1.0.8",
35
- "@rbxts/t": "^3.2.1",
36
- "@rbxts/trove": "^1.3.0"
22
+ "typescript": "^5.9.3"
37
23
  }
38
- }
24
+ }
package/src/Client.lua ADDED
@@ -0,0 +1,395 @@
1
+ --!strict
2
+ local Players = game:GetService('Players');
3
+ local UserInputService = game:GetService('UserInputService');
4
+ local Workspace = game:GetService('Workspace');
5
+
6
+ local Shared = require(script.Parent.Shared);
7
+ local isTypeScriptEnv = script.Parent.Name == 'src';
8
+ local dependencies = if isTypeScriptEnv then script.Parent.Parent.Parent else script.Parent.Parent;
9
+ local Charm = require(isTypeScriptEnv and dependencies.charm or dependencies.Charm);
10
+ local Trove = require(isTypeScriptEnv and dependencies['sleitnick-trove'] or dependencies.Trove);
11
+
12
+ type TouchButton = {
13
+ setIcon: (self: TouchButton, icon: string) -> (),
14
+ setSize: (self: TouchButton, size: UDim2) -> (),
15
+ setPosition: (self: TouchButton, position: UDim2) -> (),
16
+ setConfig: (self: TouchButton, config: Shared.TouchButtonConfig) -> (),
17
+ destroy: (self: TouchButton) -> (),
18
+ };
19
+
20
+ type TouchButtonOptions = {
21
+ name: string,
22
+ icon: string,
23
+ size: UDim2,
24
+ position: UDim2,
25
+ sinkInput: boolean?,
26
+ onPress: (() -> ())?,
27
+ onRelease: (() -> ())?,
28
+ };
29
+
30
+ local localPlayer = Players.LocalPlayer;
31
+ local camera = Workspace.CurrentCamera :: Camera;
32
+
33
+ local touchGui: ScreenGui?;
34
+ local jumpBtn: Frame?;
35
+
36
+ local initialized = false;
37
+
38
+ local EDITING_MODE_BUTTON_COLOR = Color3.fromRGB(15, 143, 255);
39
+ local MIN_RESIZE = 40;
40
+
41
+ local function getJumpButtonLayout()
42
+ local minAxis = math.min(camera.ViewportSize.X, camera.ViewportSize.Y);
43
+ local isSmallScreen = minAxis <= 500;
44
+ local jumpButtonSize = if isSmallScreen then 70 else 120;
45
+
46
+ return {
47
+ size = UDim2.fromOffset(jumpButtonSize, jumpButtonSize),
48
+ position = if isSmallScreen
49
+ then UDim2.new(1, -(jumpButtonSize * 1.5 - 10), 1, -jumpButtonSize - 20)
50
+ else UDim2.new(1, -(jumpButtonSize * 1.5 - 10), 1, -jumpButtonSize * 1.75),
51
+ };
52
+ end;
53
+
54
+ local function getTouchGui()
55
+ if touchGui and jumpBtn then
56
+ return touchGui, jumpBtn;
57
+ end;
58
+
59
+ local newTouchGui = Instance.new('ScreenGui');
60
+ newTouchGui.Name = 'CustomTouchGui';
61
+ newTouchGui.ResetOnSpawn = false;
62
+ newTouchGui.Parent = localPlayer:WaitForChild('PlayerGui');
63
+ touchGui = newTouchGui;
64
+
65
+ local newJumpBtn = Instance.new('Frame');
66
+ newJumpBtn.Name = 'Jump';
67
+ newJumpBtn.BackgroundTransparency = 1;
68
+
69
+ local function updateLayout()
70
+ local jumpBtnLayout = getJumpButtonLayout();
71
+ newJumpBtn.Position = jumpBtnLayout.position;
72
+ newJumpBtn.Size = jumpBtnLayout.size;
73
+ end;
74
+
75
+ camera:GetPropertyChangedSignal('ViewportSize'):Connect(updateLayout);
76
+ updateLayout();
77
+
78
+ newJumpBtn.Parent = newTouchGui;
79
+ jumpBtn = newJumpBtn;
80
+
81
+ local characterExists = Charm.atom(localPlayer.Character ~= nil);
82
+ local lastInputType = Charm.atom(UserInputService:GetLastInputType());
83
+
84
+ Charm.effect(function()
85
+ local charExists = characterExists();
86
+ local inputType = lastInputType();
87
+
88
+ newTouchGui.Enabled = (inputType == Enum.UserInputType.Touch) and charExists;
89
+ end);
90
+
91
+ localPlayer.CharacterAdded:Connect(function()
92
+ characterExists(true);
93
+ end);
94
+ localPlayer.CharacterRemoving:Connect(function()
95
+ characterExists(false);
96
+ end);
97
+
98
+ UserInputService.LastInputTypeChanged:Connect(lastInputType);
99
+
100
+ return newTouchGui, newJumpBtn;
101
+ end;
102
+
103
+ local Client = {};
104
+ Client.__index = Client;
105
+
106
+ Client.configEditingMode = Charm.atom(false);
107
+ Client.touchButtons = {} :: { TouchButton };
108
+
109
+ function Client._init()
110
+ if initialized then return; end;
111
+ initialized = true;
112
+
113
+ local editingTrove = Trove.new();
114
+
115
+ Charm.effect(function()
116
+ local isEditing = Client.configEditingMode();
117
+ if isEditing then
118
+ local function createButton(props: { name: string, text: string, backgroundColor: Color3, offsetY: number })
119
+ local btn = Instance.new('TextButton');
120
+ btn.Name = props.name;
121
+ btn.AnchorPoint = Vector2.new(0.5, 0.5);
122
+ btn.BackgroundColor3 = props.backgroundColor;
123
+ btn.BackgroundTransparency = 0.25;
124
+ btn.FontFace = Font.new('rbxasset://fonts/families/GothamSSm.json', Enum.FontWeight.Medium, Enum.FontStyle.Normal);
125
+ btn.Position = UDim2.new(0.5, 0, 0.5, props.offsetY);
126
+ btn.Size = UDim2.fromOffset(120, 32);
127
+ btn.Text = props.text;
128
+ btn.TextColor3 = Color3.new(1, 1, 1);
129
+ btn.TextSize = 16;
130
+ btn.Parent = touchGui;
131
+ editingTrove:Add(btn);
132
+
133
+ local uiCorner = Instance.new('UICorner');
134
+ uiCorner.CornerRadius = UDim.new(0, 5);
135
+ uiCorner.Parent = btn;
136
+
137
+ return btn;
138
+ end;
139
+
140
+ createButton({
141
+ name = 'Reset',
142
+ text = 'Reset Buttons',
143
+ backgroundColor = Color3.new(),
144
+ offsetY = -19,
145
+ }).MouseButton1Click:Connect(function()
146
+ for _, touchBtn in Client.touchButtons do
147
+ touchBtn:_resetConfigToDefault();
148
+ end;
149
+ end);
150
+
151
+ createButton({
152
+ name = 'Finish',
153
+ text = 'Finish Editing',
154
+ backgroundColor = Color3.fromRGB(30, 175, 30),
155
+ offsetY = 19,
156
+ }).MouseButton1Click:Connect(function()
157
+ Client.configEditingMode(false);
158
+ end);
159
+ else
160
+ editingTrove:Clean();
161
+ end;
162
+ end);
163
+ end;
164
+
165
+ function Client.new(options: TouchButtonOptions)
166
+ Client._init();
167
+
168
+ for _, otherTouchBtn in Client.touchButtons do
169
+ assert(otherTouchBtn._name ~= options.name, `A TouchButton with the name {options.name} already exists`);
170
+ end;
171
+
172
+ local self = setmetatable({}, Client);
173
+
174
+ self._name = options.name;
175
+ self._desiredBtnColor = Color3.fromRGB(255, 255, 255);
176
+ self._defaultConfig = {
177
+ position = options.position,
178
+ size = options.size,
179
+ };
180
+ self._configUpdateScheduled = false;
181
+
182
+ task.spawn(function()
183
+ local config = Shared.getTouchButtonConfig:InvokeServer(options.name);
184
+ if not config then return; end;
185
+ self:setConfig(config);
186
+ end);
187
+
188
+ local touchBtn = Instance.new('ImageButton');
189
+ touchBtn.Name = 'TouchButton';
190
+ touchBtn.Active = if options.sinkInput then true else false;
191
+ touchBtn.Image = 'http://www.roblox.com/asset/?id=15340864550';
192
+ touchBtn.ImageColor3 = Color3.fromRGB(255, 255, 255);
193
+ touchBtn.ImageTransparency = 0.5;
194
+ touchBtn.AnchorPoint = Vector2.new(0.5, 0.5);
195
+ touchBtn.BackgroundTransparency = 1;
196
+ touchBtn.Size = UDim2.fromScale(1, 1);
197
+
198
+ local iconImage = Instance.new('ImageLabel');
199
+ iconImage.Name = 'Icon';
200
+ iconImage.AnchorPoint = Vector2.new(0.5, 0.5);
201
+ iconImage.BackgroundTransparency = 1;
202
+ iconImage.ImageColor3 = self._desiredBtnColor;
203
+ iconImage.ImageTransparency = 0.2;
204
+ iconImage.Position = UDim2.fromScale(0.5, 0.5);
205
+ iconImage.Size = UDim2.fromScale(0.56, 0.56);
206
+ iconImage.Parent = touchBtn;
207
+
208
+ self._touchBtn = touchBtn;
209
+
210
+ touchBtn.InputBegan:Connect(function(input)
211
+ if (input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch) then return; end;
212
+ if input.UserInputState ~= Enum.UserInputState.Begin then return; end;
213
+
214
+ if Client.configEditingMode() then return; end;
215
+
216
+ touchBtn.ImageColor3 = Color3.fromRGB(200, 200, 200);
217
+ iconImage.ImageColor3 = Color3.fromRGB(200, 200, 200);
218
+
219
+ if options.onPress then options.onPress(); end;
220
+
221
+ local connection;
222
+ connection = input:GetPropertyChangedSignal('UserInputState'):Connect(function()
223
+ if input.UserInputState ~= Enum.UserInputState.End then return; end;
224
+
225
+ connection:Disconnect();
226
+
227
+ touchBtn.ImageColor3 = Color3.fromRGB(255, 255, 255);
228
+ iconImage.ImageColor3 = self._desiredBtnColor;
229
+
230
+ if options.onRelease then options.onRelease(); end;
231
+ end);
232
+ end);
233
+
234
+ local editingTrove = Trove.new();
235
+ local lastActive = touchBtn.Active;
236
+
237
+ self._editEffect = Charm.effect(function()
238
+ local isEditing = Client.configEditingMode();
239
+
240
+ if isEditing then
241
+ lastActive = touchBtn.Active;
242
+
243
+ touchBtn.Active = true;
244
+ touchBtn.ImageColor3 = EDITING_MODE_BUTTON_COLOR;
245
+ iconImage.ImageColor3 = EDITING_MODE_BUTTON_COLOR;
246
+
247
+ local resizeBtn = Instance.new('ImageButton');
248
+ resizeBtn.AnchorPoint = Vector2.new(0.5, 0.5);
249
+ resizeBtn.BackgroundTransparency = 1;
250
+ resizeBtn.Image = 'http://www.roblox.com/asset/?id=101680714548913';
251
+ resizeBtn.Position = UDim2.fromScale(0.82, 0.82);
252
+ resizeBtn.Size = UDim2.fromOffset(18, 18);
253
+ resizeBtn.Parent = touchBtn;
254
+ editingTrove:Add(resizeBtn);
255
+
256
+ resizeBtn.InputBegan:Connect(function(input)
257
+ if (input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch) then return; end;
258
+ if input.UserInputState ~= Enum.UserInputState.Begin then return; end;
259
+
260
+ local parent = touchBtn.Parent :: GuiObject;
261
+ local parentSize = parent.AbsoluteSize;
262
+ local initialAbsSize = touchBtn.AbsoluteSize;
263
+ local initialPos = Vector2.new(input.Position.X, input.Position.Y);
264
+
265
+ local moveConn = UserInputService.InputChanged:Connect(function(moveInput)
266
+ if (moveInput.UserInputType ~= Enum.UserInputType.MouseMovement) and (moveInput.UserInputType ~= Enum.UserInputType.Touch) then return; end;
267
+
268
+ local delta = Vector2.new(moveInput.Position.X, moveInput.Position.Y) - initialPos;
269
+ local maxDelta = math.max(delta.X, delta.Y);
270
+ local newAbsSize = initialAbsSize.X + maxDelta;
271
+
272
+ local finalAbsSize = math.max(MIN_RESIZE, newAbsSize);
273
+ local finalScale = finalAbsSize / parentSize.X;
274
+
275
+ self:setSize(UDim2.fromScale(finalScale, finalScale));
276
+ end);
277
+
278
+ local endConn;
279
+ endConn = UserInputService.InputEnded:Connect(function(endInput)
280
+ if (endInput.UserInputType ~= Enum.UserInputType.MouseButton1) and (endInput.UserInputType ~= Enum.UserInputType.Touch) then return; end;
281
+
282
+ moveConn:Disconnect();
283
+ endConn:Disconnect();
284
+ end);
285
+ end);
286
+
287
+ editingTrove:Add(touchBtn.InputBegan:Connect(function(input)
288
+ if (input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch) then return; end;
289
+ if input.UserInputState ~= Enum.UserInputState.Begin then return; end;
290
+
291
+ local parent = touchBtn.Parent :: GuiObject;
292
+ local parentSize = parent.AbsoluteSize;
293
+ local initialInputPos = Vector2.new(input.Position.X, input.Position.Y);
294
+ local initialBtnPos = touchBtn.Position;
295
+
296
+ local moveConn = UserInputService.InputChanged:Connect(function(moveInput)
297
+ if (moveInput.UserInputType ~= Enum.UserInputType.MouseMovement) and (moveInput.UserInputType ~= Enum.UserInputType.Touch) then return; end;
298
+
299
+ local currentPos = Vector2.new(moveInput.Position.X, moveInput.Position.Y);
300
+ local delta = currentPos - initialInputPos;
301
+
302
+ local deltaScale = Vector2.new(delta.X / parentSize.X, delta.Y / parentSize.Y);
303
+
304
+ self:setPosition(UDim2.fromScale(initialBtnPos.X.Scale + deltaScale.X, initialBtnPos.Y.Scale + deltaScale.Y));
305
+ end);
306
+
307
+ local endConn;
308
+ endConn = UserInputService.InputEnded:Connect(function(endInput)
309
+ if (endInput.UserInputType ~= Enum.UserInputType.MouseButton1) and (endInput.UserInputType ~= Enum.UserInputType.Touch) then return; end;
310
+
311
+ moveConn:Disconnect();
312
+ endConn:Disconnect();
313
+ end);
314
+ end));
315
+ else
316
+ editingTrove:Clean();
317
+
318
+ touchBtn.Active = lastActive;
319
+ touchBtn.ImageColor3 = Color3.fromRGB(255, 255, 255);
320
+ iconImage.ImageColor3 = self._desiredBtnColor;
321
+ end;
322
+ end);
323
+
324
+ self:setIcon(options.icon);
325
+ self:setSize(options.size);
326
+ self:setPosition(options.position);
327
+
328
+ local _, currentJumpBtn = getTouchGui();
329
+ touchBtn.Parent = currentJumpBtn;
330
+
331
+ table.insert(Client.touchButtons, self);
332
+
333
+ return self;
334
+ end;
335
+
336
+ function Client:setIcon(icon: string)
337
+ self._touchBtn.Icon.Image = icon;
338
+ end;
339
+
340
+ function Client:setColor(color: Color3)
341
+ self._desiredBtnColor = color;
342
+ self._touchBtn.Icon.ImageColor3 = color;
343
+ end;
344
+
345
+ function Client:setSize(size: UDim2)
346
+ self._touchBtn.Size = size;
347
+ self:_scheduleConfigUpdate();
348
+ end;
349
+
350
+ function Client:setPosition(position: UDim2)
351
+ self._touchBtn.Position = position;
352
+ self:_scheduleConfigUpdate();
353
+ end;
354
+
355
+ function Client:setConfig(config: Shared.TouchButtonConfig)
356
+ self:setPosition(config.position);
357
+ self:setSize(config.size);
358
+ end;
359
+
360
+ function Client:_scheduleConfigUpdate()
361
+ if self._configUpdateScheduled then return; end;
362
+ self._configUpdateScheduled = true;
363
+
364
+ task.defer(function()
365
+ self._configUpdateScheduled = false;
366
+ self:_updateConfig();
367
+ end);
368
+ end;
369
+
370
+ function Client:_updateConfig()
371
+ Shared.setTouchButtonConfig:FireServer(self._name, {
372
+ position = self._touchBtn.Position,
373
+ size = self._touchBtn.Size,
374
+ });
375
+ end;
376
+
377
+ function Client:_resetConfigToDefault()
378
+ self:setConfig(self._defaultConfig);
379
+ end;
380
+
381
+ function Client:destroy()
382
+ self._touchBtn:Destroy();
383
+
384
+ if self._editEffect then
385
+ self._editEffect();
386
+ self._editEffect = nil;
387
+ end
388
+
389
+ local index = table.find(Client.touchButtons, self);
390
+ if index then
391
+ table.remove(Client.touchButtons, index);
392
+ end;
393
+ end;
394
+
395
+ return Client;
package/src/Server.lua ADDED
@@ -0,0 +1,161 @@
1
+ --!strict
2
+ local DataStoreService = game:GetService('DataStoreService');
3
+ local Players = game:GetService('Players');
4
+
5
+ local Shared = require(script.Parent.Shared);
6
+ local isTypeScriptEnv = script.Parent.Name == 'src';
7
+ local dependencies = if isTypeScriptEnv then script.Parent.Parent.Parent else script.Parent.Parent;
8
+ local Signal = require(isTypeScriptEnv and dependencies['sleitnick-signal'] or dependencies.Signal);
9
+
10
+ type DataStoreEntry = { [string]: Shared.TouchButtonConfig };
11
+ type SerializedTouchButtonConfig = { [string]: {number} };
12
+ type SerializedDataStoreEntry = { [string]: SerializedTouchButtonConfig };
13
+
14
+ local entriesCache: { [Player]: DataStoreEntry } = {};
15
+ local playerDataLoaded = Signal.new();
16
+ local initialized = false;
17
+
18
+ local function getDataStoreKeyForPlayer(player: Player)
19
+ return `Player{player.UserId}`;
20
+ end;
21
+
22
+ local function waitForEntry(player: Player)
23
+ local entry = entriesCache[player];
24
+ if not entry then
25
+ local loadedPlayer, loadedEntry;
26
+ repeat
27
+ loadedPlayer, loadedEntry = playerDataLoaded:Wait();
28
+ until loadedPlayer == player;
29
+ entry = loadedEntry;
30
+ end;
31
+ return entry;
32
+ end;
33
+
34
+ local function serializeEntry(entry: DataStoreEntry)
35
+ local res: SerializedDataStoreEntry = {};
36
+
37
+ for buttonName, props in entry do
38
+ local serializedProps: SerializedTouchButtonConfig = {};
39
+
40
+ for propKey, propValue in props do
41
+ local serializedProp;
42
+
43
+ if typeof(propValue) == 'Vector2' then
44
+ serializedProp = { propValue.X, propValue.Y };
45
+ elseif typeof(propValue) == 'UDim2' then
46
+ serializedProp = { propValue.X.Scale, propValue.X.Offset, propValue.Y.Scale, propValue.Y.Offset };
47
+ end;
48
+
49
+ if serializedProp then
50
+ serializedProps[propKey] = serializedProp;
51
+ end;
52
+ end;
53
+
54
+ res[buttonName] = serializedProps;
55
+ end;
56
+
57
+ return res;
58
+ end;
59
+
60
+ local function deserializeEntry(entry: SerializedDataStoreEntry)
61
+ local res: DataStoreEntry = {};
62
+
63
+ for buttonName, serializedProps in entry do
64
+ local props: Shared.TouchButtonConfig = {};
65
+
66
+ for propKey, serializedValue in serializedProps do
67
+ local deserializedProp;
68
+
69
+ if #serializedValue == 2 then
70
+ deserializedProp = Vector2.new(serializedValue[1], serializedValue[2]);
71
+ elseif #serializedValue == 4 then
72
+ deserializedProp = UDim2.new(serializedValue[1], serializedValue[2], serializedValue[3], serializedValue[4]);
73
+ end;
74
+
75
+ props[propKey] = deserializedProp;
76
+ end;
77
+
78
+ res[buttonName] = props;
79
+ end;
80
+
81
+ return res;
82
+ end;
83
+
84
+ local function isDictOfSize(dict: { [unknown]: unknown }, size: number)
85
+ local dictSize = 0;
86
+ for _ in dict do
87
+ dictSize += 1;
88
+ if dictSize > size then return false; end;
89
+ end;
90
+ return dictSize == size;
91
+ end;
92
+
93
+ local Server = {};
94
+
95
+ function Server.init(validTouchButtonNames: { string })
96
+ assert(not initialized, 'TouchButton.Server already initialized');
97
+ initialized = true;
98
+
99
+ local buttonsStore = DataStoreService:GetDataStore('TouchButtonConfigs');
100
+
101
+ Shared.getTouchButtonConfig.OnServerInvoke = function(player: Player, buttonName: string)
102
+ local entry = waitForEntry(player);
103
+ return entry[buttonName];
104
+ end;
105
+
106
+ Shared.setTouchButtonConfig.OnServerEvent:Connect(function(player: Player, buttonName: string, config: Shared.TouchButtonConfig)
107
+ assert(table.find(validTouchButtonNames, buttonName), `TouchButton: {buttonName} is not a valid savable TouchButton name`);
108
+
109
+ if typeof(config) ~= 'table' then return; end;
110
+ if not config.size then return; end;
111
+ if not config.position then return; end;
112
+ if not isDictOfSize(config, 2) then return; end;
113
+
114
+ local entry = waitForEntry(player);
115
+ entry[buttonName] = config;
116
+ end);
117
+
118
+ local function onPlayerAdded(player: Player)
119
+ local key = getDataStoreKeyForPlayer(player);
120
+
121
+ local suc, entryOrUndefinedOrErr = pcall(function()
122
+ return buttonsStore:GetAsync(key);
123
+ end);
124
+ if not suc then
125
+ warn('TouchButton: Failed to load DataStore entry:', entryOrUndefinedOrErr);
126
+ return;
127
+ end;
128
+
129
+ if not player:IsDescendantOf(Players) then return; end;
130
+
131
+ local entry = if entryOrUndefinedOrErr then deserializeEntry(entryOrUndefinedOrErr) else {};
132
+
133
+ entriesCache[player] = entry;
134
+ playerDataLoaded:Fire(player, entry);
135
+ end;
136
+
137
+ local function onPlayerRemoving(player: Player)
138
+ local entry = entriesCache[player];
139
+ if not entry then return; end;
140
+
141
+ local key = getDataStoreKeyForPlayer(player);
142
+ local serialized = serializeEntry(entry);
143
+
144
+ local suc, err = pcall(function()
145
+ buttonsStore:SetAsync(key, serialized, { player.UserId });
146
+ end);
147
+ if not suc then
148
+ warn(`TouchButton: Failed to save data for {player.Name}:`, err);
149
+ end;
150
+
151
+ entriesCache[player] = nil;
152
+ end;
153
+
154
+ for _, player in Players:GetPlayers() do
155
+ task.spawn(onPlayerAdded, player);
156
+ end;
157
+ Players.PlayerAdded:Connect(onPlayerAdded);
158
+ Players.PlayerRemoving:Connect(onPlayerRemoving);
159
+ end;
160
+
161
+ return Server;
package/src/Shared.lua ADDED
@@ -0,0 +1,38 @@
1
+ --!strict
2
+ local RunService = game:GetService('RunService');
3
+
4
+ export type TouchButtonConfig = {
5
+ position: UDim2,
6
+ size: UDim2,
7
+ };
8
+
9
+ local IS_SERVER = RunService:IsServer();
10
+
11
+ local function getRemoteEvent(name: string)
12
+ if IS_SERVER then
13
+ local remote = Instance.new('RemoteEvent');
14
+ remote.Name = name;
15
+ remote.Parent = script;
16
+ return remote;
17
+ end;
18
+
19
+ return script:WaitForChild(name) :: RemoteEvent;
20
+ end;
21
+
22
+ local function getRemoteFunction(name: string)
23
+ if IS_SERVER then
24
+ local remote = Instance.new('RemoteFunction');
25
+ remote.Name = name;
26
+ remote.Parent = script;
27
+ return remote;
28
+ end;
29
+
30
+ return script:WaitForChild(name) :: RemoteFunction;
31
+ end;
32
+
33
+ local Shared = {};
34
+
35
+ Shared.getTouchButtonConfig = getRemoteFunction('GetTouchButtonConfig');
36
+ Shared.setTouchButtonConfig = getRemoteEvent('SetTouchButtonConfig');
37
+
38
+ return Shared;
package/src/index.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ declare namespace TouchButton {
2
+ interface TouchButtonConfig {
3
+ position: UDim2;
4
+ size: UDim2;
5
+ }
6
+
7
+ interface TouchButtonOptions {
8
+ name: string;
9
+ icon: string;
10
+ size: UDim2;
11
+ position: UDim2;
12
+ sinkInput?: boolean;
13
+ onPress?: () => void;
14
+ onRelease?: () => void;
15
+ }
16
+
17
+ namespace Server {
18
+ function init(validTouchButtonNames: string[]): void;
19
+ }
20
+
21
+ class Client {
22
+ static touchButtons: Client[];
23
+ static configEditingMode: (enabled?: boolean) => boolean;
24
+
25
+ constructor(options: TouchButtonOptions);
26
+
27
+ setIcon(icon: string): void;
28
+ setColor(color: Color3): void;
29
+ setSize(size: UDim2): void;
30
+ setPosition(position: UDim2): void;
31
+ setConfig(config: TouchButtonConfig): void;
32
+ destroy(): void;
33
+ }
34
+ }
35
+
36
+ export = TouchButton;
package/src/init.lua ADDED
@@ -0,0 +1,12 @@
1
+ --!strict
2
+ local RunService = game:GetService('RunService');
3
+
4
+ local TouchButton = {};
5
+
6
+ if RunService:IsServer() then
7
+ TouchButton.Server = require(script.Server);
8
+ else
9
+ TouchButton.Client = require(script.Client);
10
+ end;
11
+
12
+ return TouchButton;
@@ -1,28 +0,0 @@
1
- import { TouchButtonConfig } from '../shared/remotes';
2
- export declare class TouchButton {
3
- static configEditingMode: import("@rbxts/charm").Atom<boolean>;
4
- static touchButtons: TouchButton[];
5
- private static initialized;
6
- private touchBtn;
7
- private name;
8
- private defaultConfig;
9
- private configUpdateScheduled;
10
- private static init;
11
- constructor(options: {
12
- name: string;
13
- icon: string;
14
- size: UDim2;
15
- position: UDim2;
16
- sinkInput?: boolean;
17
- onPress?: () => void;
18
- onRelease?: () => void;
19
- });
20
- setIcon(icon: string): void;
21
- setSize(size: UDim2): void;
22
- setPosition(position: UDim2): void;
23
- setConfig(config: TouchButtonConfig): void;
24
- private scheduleConfigUpdate;
25
- private updateConfig;
26
- private resetConfigToDefault;
27
- destroy(): void;
28
- }
@@ -1,334 +0,0 @@
1
- -- Compiled with roblox-ts v3.0.0
2
- local TS = _G[script]
3
- local observeProperty = TS.import(script, TS.getModule(script, "@rbxts", "roblox-observers").src).observeProperty
4
- local _services = TS.import(script, TS.getModule(script, "@rbxts", "services"))
5
- local Players = _services.Players
6
- local UserInputService = _services.UserInputService
7
- local Workspace = _services.Workspace
8
- local remotes = TS.import(script, script.Parent.Parent, "shared", "remotes").remotes
9
- local _charm = TS.import(script, TS.getModule(script, "@rbxts", "charm"))
10
- local atom = _charm.atom
11
- local effect = _charm.effect
12
- local Trove = TS.import(script, TS.getModule(script, "@rbxts", "trove").out).Trove
13
- local localPlayer = Players.LocalPlayer
14
- local camera = Workspace.CurrentCamera
15
- local touchGui
16
- local jumpBtn
17
- local EDITING_MODE_BUTTON_COLOR = Color3.fromRGB(15, 143, 255)
18
- local MIN_RESIZE = 40
19
- -- This is taken from TouchJump.lua in PlayerScripts.
20
- local function getJumpButtonLayout()
21
- local minAxis = math.min(camera.ViewportSize.X, camera.ViewportSize.Y)
22
- local isSmallScreen = minAxis <= 500
23
- local jumpButtonSize = if isSmallScreen then 70 else 120
24
- return {
25
- size = UDim2.fromOffset(jumpButtonSize, jumpButtonSize),
26
- position = if isSmallScreen then UDim2.new(1, -(jumpButtonSize * 1.5 - 10), 1, -jumpButtonSize - 20) else UDim2.new(1, -(jumpButtonSize * 1.5 - 10), 1, -jumpButtonSize * 1.75),
27
- }
28
- end
29
- local function getTouchGui()
30
- if touchGui and jumpBtn then
31
- return { touchGui, jumpBtn }
32
- end
33
- touchGui = Instance.new("ScreenGui")
34
- touchGui.Name = "CustomTouchGui"
35
- touchGui.ResetOnSpawn = false
36
- touchGui.Parent = localPlayer.PlayerGui
37
- jumpBtn = Instance.new("Frame")
38
- jumpBtn.Name = "Jump"
39
- jumpBtn.BackgroundTransparency = 1
40
- observeProperty(camera, "ViewportSize", function()
41
- local jumpBtnLayout = getJumpButtonLayout()
42
- jumpBtn.Position = jumpBtnLayout.position
43
- jumpBtn.Size = jumpBtnLayout.size
44
- end)
45
- jumpBtn.Parent = touchGui
46
- local characterExists = atom(not not localPlayer.Character)
47
- local lastInputType = atom(UserInputService:GetLastInputType())
48
- effect(function()
49
- local charExists = characterExists()
50
- local inputType = lastInputType()
51
- touchGui.Enabled = (inputType == Enum.UserInputType.Touch) and charExists
52
- end)
53
- localPlayer.CharacterAdded:Connect(function()
54
- characterExists(true)
55
- end)
56
- localPlayer.CharacterRemoving:Connect(function()
57
- characterExists(false)
58
- end)
59
- UserInputService.LastInputTypeChanged:Connect(lastInputType)
60
- return { touchGui, jumpBtn }
61
- end
62
- local TouchButton
63
- do
64
- TouchButton = setmetatable({}, {
65
- __tostring = function()
66
- return "TouchButton"
67
- end,
68
- })
69
- TouchButton.__index = TouchButton
70
- function TouchButton.new(...)
71
- local self = setmetatable({}, TouchButton)
72
- return self:constructor(...) or self
73
- end
74
- function TouchButton:constructor(options)
75
- self.configUpdateScheduled = false
76
- TouchButton:init()
77
- for _1, otherTouchBtn in TouchButton.touchButtons do
78
- local _arg0 = otherTouchBtn.name ~= options.name
79
- local _arg1 = `A TouchButton with the name {options.name} already exists`
80
- assert(_arg0, _arg1)
81
- end
82
- self.name = options.name
83
- self.defaultConfig = {
84
- position = options.position,
85
- size = options.size,
86
- }
87
- local configPromise = remotes.getTouchButtonConfig:request(options.name)
88
- local touchBtn = Instance.new("ImageButton")
89
- touchBtn.Name = "TouchButton"
90
- touchBtn.Active = not not options.sinkInput
91
- touchBtn.Image = "http://www.roblox.com/asset/?id=15340864550"
92
- touchBtn.ImageColor3 = Color3.fromRGB(255, 255, 255)
93
- touchBtn.ImageTransparency = 0.5
94
- touchBtn.AnchorPoint = Vector2.new(0.5, 0.5)
95
- touchBtn.BackgroundTransparency = 1
96
- touchBtn.Size = UDim2.fromScale(1, 1)
97
- local iconImage = Instance.new("ImageLabel")
98
- iconImage.Name = "Icon"
99
- iconImage.AnchorPoint = Vector2.new(0.5, 0.5)
100
- iconImage.BackgroundTransparency = 1
101
- iconImage.ImageTransparency = 0.2
102
- iconImage.Position = UDim2.fromScale(0.5, 0.5)
103
- iconImage.Size = UDim2.fromScale(0.56, 0.56)
104
- iconImage.Parent = touchBtn
105
- touchBtn.InputBegan:Connect(function(input)
106
- if (input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch) then
107
- return nil
108
- end
109
- if input.UserInputState ~= Enum.UserInputState.Begin then
110
- return nil
111
- end
112
- if TouchButton.configEditingMode() then
113
- return nil
114
- end
115
- touchBtn.ImageColor3 = Color3.fromRGB(200, 200, 200)
116
- iconImage.ImageColor3 = Color3.fromRGB(200, 200, 200)
117
- local _result = options.onPress
118
- if _result ~= nil then
119
- _result()
120
- end
121
- local connection
122
- connection = input:GetPropertyChangedSignal("UserInputState"):Connect(function()
123
- if input.UserInputState ~= Enum.UserInputState.End then
124
- return nil
125
- end
126
- connection:Disconnect()
127
- touchBtn.ImageColor3 = Color3.fromRGB(255, 255, 255)
128
- iconImage.ImageColor3 = Color3.fromRGB(255, 255, 255)
129
- local _result_1 = options.onRelease
130
- if _result_1 ~= nil then
131
- _result_1()
132
- end
133
- end)
134
- end)
135
- local editingTrove = Trove.new()
136
- local lastActive = touchBtn.Active
137
- effect(function()
138
- local isEditing = TouchButton.configEditingMode()
139
- if isEditing then
140
- lastActive = touchBtn.Active
141
- touchBtn.Active = true
142
- touchBtn.ImageColor3 = EDITING_MODE_BUTTON_COLOR
143
- iconImage.ImageColor3 = EDITING_MODE_BUTTON_COLOR
144
- local resizeBtn = Instance.new("ImageButton")
145
- resizeBtn.AnchorPoint = Vector2.new(0.5, 0.5)
146
- resizeBtn.BackgroundTransparency = 1
147
- resizeBtn.Image = "http://www.roblox.com/asset/?id=101680714548913"
148
- resizeBtn.Position = UDim2.fromScale(0.82, 0.82)
149
- resizeBtn.Size = UDim2.fromOffset(18, 18)
150
- resizeBtn.Parent = touchBtn
151
- editingTrove:add(resizeBtn)
152
- resizeBtn.InputBegan:Connect(function(input)
153
- if (input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch) then
154
- return nil
155
- end
156
- if input.UserInputState ~= Enum.UserInputState.Begin then
157
- return nil
158
- end
159
- local parentSize = (touchBtn.Parent).AbsoluteSize
160
- local initialAbsSize = touchBtn.AbsoluteSize
161
- local initialPos = Vector2.new(input.Position.X, input.Position.Y)
162
- local moveConn = UserInputService.InputChanged:Connect(function(moveInput)
163
- if (moveInput.UserInputType ~= Enum.UserInputType.MouseMovement) and (moveInput.UserInputType ~= Enum.UserInputType.Touch) then
164
- return nil
165
- end
166
- local delta = Vector2.new(moveInput.Position.X, moveInput.Position.Y) - initialPos
167
- local maxDelta = math.max(delta.X, delta.Y)
168
- local newAbsSize = initialAbsSize.X + maxDelta
169
- local finalAbsSize = math.max(MIN_RESIZE, newAbsSize)
170
- local finalScale = finalAbsSize / parentSize.X
171
- self:setSize(UDim2.fromScale(finalScale, finalScale))
172
- end)
173
- local endConn
174
- endConn = UserInputService.InputEnded:Connect(function(endInput)
175
- if (endInput.UserInputType ~= Enum.UserInputType.MouseButton1) and (endInput.UserInputType ~= Enum.UserInputType.Touch) then
176
- return nil
177
- end
178
- moveConn:Disconnect()
179
- endConn:Disconnect()
180
- end)
181
- end)
182
- editingTrove:add(touchBtn.InputBegan:Connect(function(input)
183
- if (input.UserInputType ~= Enum.UserInputType.MouseButton1) and (input.UserInputType ~= Enum.UserInputType.Touch) then
184
- return nil
185
- end
186
- if input.UserInputState ~= Enum.UserInputState.Begin then
187
- return nil
188
- end
189
- local parentSize = (touchBtn.Parent).AbsoluteSize
190
- local initialInputPos = Vector2.new(input.Position.X, input.Position.Y)
191
- local initialBtnPos = touchBtn.Position
192
- local moveConn = UserInputService.InputChanged:Connect(function(moveInput)
193
- if (moveInput.UserInputType ~= Enum.UserInputType.MouseMovement) and (moveInput.UserInputType ~= Enum.UserInputType.Touch) then
194
- return nil
195
- end
196
- local currentPos = Vector2.new(moveInput.Position.X, moveInput.Position.Y)
197
- local delta = currentPos - initialInputPos
198
- local deltaScale = Vector2.new(delta.X / parentSize.X, delta.Y / parentSize.Y)
199
- self:setPosition(UDim2.fromScale(initialBtnPos.X.Scale + deltaScale.X, initialBtnPos.Y.Scale + deltaScale.Y))
200
- end)
201
- local endConn
202
- endConn = UserInputService.InputEnded:Connect(function(endInput)
203
- if (endInput.UserInputType ~= Enum.UserInputType.MouseButton1) and (endInput.UserInputType ~= Enum.UserInputType.Touch) then
204
- return nil
205
- end
206
- moveConn:Disconnect()
207
- endConn:Disconnect()
208
- end)
209
- end))
210
- else
211
- editingTrove:clean()
212
- touchBtn.Active = lastActive
213
- touchBtn.ImageColor3 = Color3.fromRGB(255, 255, 255)
214
- iconImage.ImageColor3 = Color3.fromRGB(255, 255, 255)
215
- end
216
- end)
217
- self.touchBtn = touchBtn
218
- self:setIcon(options.icon)
219
- self:setSize(options.size)
220
- self:setPosition(options.position)
221
- configPromise:andThen(function(config)
222
- if not config then
223
- return nil
224
- end
225
- self:setConfig(config)
226
- end)
227
- local _binding = getTouchGui()
228
- local _ = _binding[1]
229
- local jumpBtn = _binding[2]
230
- touchBtn.Parent = jumpBtn
231
- local _touchButtons = TouchButton.touchButtons
232
- local _self = self
233
- table.insert(_touchButtons, _self)
234
- end
235
- function TouchButton:init()
236
- if self.initialized then
237
- return nil
238
- end
239
- self.initialized = true
240
- local editingTrove = Trove.new()
241
- effect(function()
242
- local isEditing = TouchButton.configEditingMode()
243
- if isEditing then
244
- local createButton = function(props)
245
- local btn = Instance.new("TextButton")
246
- btn.Name = props.name
247
- btn.AnchorPoint = Vector2.new(0.5, 0.5)
248
- btn.BackgroundColor3 = props.backgroundColor
249
- btn.BackgroundTransparency = 0.25
250
- btn.FontFace = Font.new("rbxasset://fonts/families/GothamSSm.json", Enum.FontWeight.Medium, Enum.FontStyle.Normal)
251
- btn.Position = UDim2.new(0.5, 0, 0.5, props.offsetY)
252
- btn.Size = UDim2.fromOffset(120, 32)
253
- btn.Text = props.text
254
- btn.TextColor3 = Color3.new(1, 1, 1)
255
- btn.TextSize = 16
256
- btn.Parent = touchGui
257
- editingTrove:add(btn)
258
- local UICorner = Instance.new("UICorner")
259
- UICorner.CornerRadius = UDim.new(0, 5)
260
- UICorner.Parent = btn
261
- return btn
262
- end
263
- createButton({
264
- name = "Reset",
265
- text = "Reset Buttons",
266
- backgroundColor = Color3.new(),
267
- offsetY = -19,
268
- }).MouseButton1Click:Connect(function()
269
- for _, touchBtn in TouchButton.touchButtons do
270
- touchBtn:resetConfigToDefault()
271
- end
272
- end)
273
- createButton({
274
- name = "Finish",
275
- text = "Finish Editing",
276
- backgroundColor = Color3.fromRGB(30, 175, 30),
277
- offsetY = 19,
278
- }).MouseButton1Click:Connect(function()
279
- self.configEditingMode(false)
280
- end)
281
- else
282
- editingTrove:clean()
283
- end
284
- end)
285
- end
286
- function TouchButton:setIcon(icon)
287
- self.touchBtn.Icon.Image = icon
288
- end
289
- function TouchButton:setSize(size)
290
- self.touchBtn.Size = size
291
- self:scheduleConfigUpdate()
292
- end
293
- function TouchButton:setPosition(position)
294
- self.touchBtn.Position = position
295
- self:scheduleConfigUpdate()
296
- end
297
- function TouchButton:setConfig(config)
298
- self:setPosition(config.position)
299
- self:setSize(config.size)
300
- end
301
- function TouchButton:scheduleConfigUpdate()
302
- if self.configUpdateScheduled then
303
- return nil
304
- end
305
- self.configUpdateScheduled = true
306
- task.defer(function()
307
- self.configUpdateScheduled = false
308
- self:updateConfig()
309
- end)
310
- end
311
- function TouchButton:updateConfig()
312
- remotes.setTouchButtonConfig:fire(self.name, {
313
- position = self.touchBtn.Position,
314
- size = self.touchBtn.Size,
315
- })
316
- end
317
- function TouchButton:resetConfigToDefault()
318
- self:setConfig(self.defaultConfig)
319
- end
320
- function TouchButton:destroy()
321
- self.touchBtn:Destroy()
322
- local _touchButtons = TouchButton.touchButtons
323
- local _touchButtons_1 = TouchButton.touchButtons
324
- local _self = self
325
- local _arg0 = (table.find(_touchButtons_1, _self) or 0) - 1
326
- table.remove(_touchButtons, _arg0 + 1)
327
- end
328
- TouchButton.configEditingMode = atom(false)
329
- TouchButton.touchButtons = {}
330
- TouchButton.initialized = false
331
- end
332
- return {
333
- TouchButton = TouchButton,
334
- }
package/out/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export { TouchButton } from './client/touch-button';
2
- export { TouchButtonServer } from './server';
package/out/init.luau DELETED
@@ -1,6 +0,0 @@
1
- -- Compiled with roblox-ts v3.0.0
2
- local TS = _G[script]
3
- local exports = {}
4
- exports.TouchButton = TS.import(script, script, "client", "touch-button").TouchButton
5
- exports.TouchButtonServer = TS.import(script, script, "server").TouchButtonServer
6
- return exports
@@ -1,3 +0,0 @@
1
- export declare namespace TouchButtonServer {
2
- function init(validTouchButtonNames: Set<string>): void;
3
- }
@@ -1,115 +0,0 @@
1
- -- Compiled with roblox-ts v3.0.0
2
- local TS = _G[script]
3
- local _services = TS.import(script, TS.getModule(script, "@rbxts", "services"))
4
- local DataStoreService = _services.DataStoreService
5
- local RunService = _services.RunService
6
- local remotes = TS.import(script, script.Parent, "shared", "remotes").remotes
7
- local observePlayers = TS.import(script, TS.getModule(script, "@rbxts", "roblox-observers").src).observePlayers
8
- local Signal = TS.import(script, TS.getModule(script, "@rbxts", "sleitnick-signal"))
9
- local entriesCache = {}
10
- local playerDataLoaded = Signal.new()
11
- local initialized = false
12
- local function getDataStoreKeyForPlayer(player)
13
- return `Player{player.UserId}`
14
- end
15
- local function waitForEntry(player)
16
- local _player = player
17
- local entry = entriesCache[_player]
18
- if not entry then
19
- local loadedPlayer
20
- local loadedEntry
21
- repeat
22
- do
23
- loadedPlayer, loadedEntry = playerDataLoaded:Wait()
24
- end
25
- until not (loadedPlayer ~= player)
26
- entry = loadedEntry
27
- end
28
- return entry
29
- end
30
- local function serializeEntry(entry)
31
- local res = {}
32
- for buttonName, props in pairs(entry) do
33
- local serializedProps = {}
34
- for propKey, propValue in pairs(props) do
35
- local serializedProp
36
- if typeof(propValue) == "Vector2" then
37
- serializedProp = { propValue.X, propValue.Y }
38
- elseif typeof(propValue) == "UDim2" then
39
- serializedProp = { propValue.X.Scale, propValue.X.Offset, propValue.Y.Scale, propValue.Y.Offset }
40
- end
41
- serializedProps[propKey] = serializedProp
42
- end
43
- res[buttonName] = serializedProps
44
- end
45
- return res
46
- end
47
- local function deserializeEntry(entry)
48
- local res = {}
49
- for buttonName, serializedProps in pairs(entry) do
50
- local props = {}
51
- for propKey, serializedValue in pairs(serializedProps) do
52
- local deserializedProp
53
- if #serializedValue == 2 then
54
- deserializedProp = Vector2.new(serializedValue[1], serializedValue[2])
55
- elseif #serializedValue == 4 then
56
- deserializedProp = UDim2.new(serializedValue[1], serializedValue[2], serializedValue[3], serializedValue[4])
57
- end
58
- props[propKey] = deserializedProp
59
- end
60
- res[buttonName] = props
61
- end
62
- return res
63
- end
64
- local TouchButtonServer = {}
65
- do
66
- local _container = TouchButtonServer
67
- local function init(validTouchButtonNames)
68
- local _arg0 = RunService:IsServer()
69
- assert(_arg0, "TouchButtonServer can only be initialized from the server")
70
- local _arg0_1 = not initialized
71
- assert(_arg0_1, "TouchButtonServer already initialized")
72
- initialized = true
73
- local buttonsStore = DataStoreService:GetDataStore("TouchButtonConfigs")
74
- remotes.getTouchButtonConfig:onRequest(function(player, buttonName)
75
- local entry = waitForEntry(player)
76
- return entry[buttonName]
77
- end)
78
- remotes.setTouchButtonConfig:connect(function(player, buttonName, config)
79
- local _validTouchButtonNames = validTouchButtonNames
80
- local _buttonName = buttonName
81
- local _arg0_2 = _validTouchButtonNames[_buttonName] ~= nil
82
- local _arg1 = `[TOUCH BUTTONS] {buttonName} is not a valid savable TouchButton name`
83
- assert(_arg0_2, _arg1)
84
- local entry = waitForEntry(player)
85
- entry[buttonName] = config
86
- end)
87
- observePlayers(function(player)
88
- local key = getDataStoreKeyForPlayer(player)
89
- local suc, entryOrUndefinedOrErr = pcall(function()
90
- return buttonsStore:GetAsync(key)
91
- end)
92
- if not suc then
93
- warn(`[TOUCH BUTTONS] Failed to load DataStore entry:`, entryOrUndefinedOrErr)
94
- return nil
95
- end
96
- local entry = if entryOrUndefinedOrErr ~= 0 and entryOrUndefinedOrErr == entryOrUndefinedOrErr and entryOrUndefinedOrErr ~= "" and entryOrUndefinedOrErr then deserializeEntry(entryOrUndefinedOrErr) else {}
97
- local _player = player
98
- local _entry = entry
99
- entriesCache[_player] = _entry
100
- playerDataLoaded:Fire(player, entry)
101
- return function()
102
- local _player_1 = player
103
- local entry = entriesCache[_player_1]
104
- if not entry then
105
- return nil
106
- end
107
- buttonsStore:SetAsync(key, serializeEntry(entry), { player.UserId })
108
- end
109
- end)
110
- end
111
- _container.init = init
112
- end
113
- return {
114
- TouchButtonServer = TouchButtonServer,
115
- }
@@ -1,9 +0,0 @@
1
- import { Server } from '@rbxts/remo';
2
- export interface TouchButtonConfig {
3
- position: UDim2;
4
- size: UDim2;
5
- }
6
- export declare const remotes: import("@rbxts/remo").Remotes<{
7
- getTouchButtonConfig: import("@rbxts/remo").RemoteBuilder<(buttonName: string) => TouchButtonConfig | undefined, Server>;
8
- setTouchButtonConfig: import("@rbxts/remo").RemoteBuilder<(buttonName: string, config: TouchButtonConfig) => void, Server>;
9
- }>;
@@ -1,16 +0,0 @@
1
- -- Compiled with roblox-ts v3.0.0
2
- local TS = _G[script]
3
- local _remo = TS.import(script, TS.getModule(script, "@rbxts", "remo").src)
4
- local createRemotes = _remo.createRemotes
5
- local remote = _remo.remote
6
- local t = TS.import(script, TS.getModule(script, "@rbxts", "t").lib.ts).t
7
- local remotes = createRemotes({
8
- getTouchButtonConfig = remote(t.string).returns(),
9
- setTouchButtonConfig = remote(t.string, t.strictInterface({
10
- position = t.UDim2,
11
- size = t.UDim2,
12
- })),
13
- })
14
- return {
15
- remotes = remotes,
16
- }