Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions src/saveslot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
## SaveSlot

<div align="center">
<a href="http://quenty.github.io/NevermoreEngine/">
<img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/docs.yml/badge.svg" alt="Documentation status" />
</a>
<a href="https://discord.gg/mhtGUS8">
<img src="https://img.shields.io/discord/385151591524597761?color=5865F2&label=discord&logo=discord&logoColor=white" alt="Discord" />
</a>
<a href="https://github.com/Quenty/NevermoreEngine/actions">
<img src="https://github.com/Quenty/NevermoreEngine/actions/workflows/build.yml/badge.svg" alt="Build and release status" />
</a>
</div>

PlayerDataStoreService wrapper for save slots

<div align="center"><a href="https://quenty.github.io/NevermoreEngine/api/SaveSlotUtils">View docs →</a></div>

## Installation

```
npm install @quenty/saveslot --save
```
14 changes: 14 additions & 0 deletions src/saveslot/default.project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "saveslot",
"globIgnorePaths": [
"**/.package-lock.json",
"**/.pnpm",
"**/.pnpm-workspace-state-v1.json",
"**/.modules.yaml",
"**/.ignored",
"**/.ignored_*"
],
"tree": {
"$path": "src"
}
}
51 changes: 51 additions & 0 deletions src/saveslot/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "@quenty/saveslot",
"version": "1.0.0",
"description": "PlayerDataStoreService wrapper for save slots",
"keywords": [
"Roblox",
"Nevermore",
"Lua",
"saveslot"
],
"bugs": {
"url": "https://github.com/Quenty/NevermoreEngine/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/Quenty/NevermoreEngine.git",
"directory": "src/saveslot/"
},
"funding": {
"type": "patreon",
"url": "https://www.patreon.com/quenty"
},
"license": "MIT",
"scripts": {
"preinstall": "npx only-allow pnpm"
},
"contributors": [
"Quenty"
],
"dependencies": {
"@quenty/adorneedata": "workspace:*",
"@quenty/baseobject": "workspace:*",
"@quenty/binder": "workspace:*",
"@quenty/brio": "workspace:*",
"@quenty/cmdrservice": "workspace:*",
"@quenty/datastore": "workspace:*",
"@quenty/instanceutils": "workspace:*",
"@quenty/loader": "workspace:*",
"@quenty/maid": "workspace:*",
"@quenty/playerbinder": "workspace:*",
"@quenty/promise": "workspace:*",
"@quenty/remoting": "workspace:*",
"@quenty/rx": "workspace:*",
"@quenty/table": "workspace:*",
"@quenty/tie": "workspace:*",
"@quenty/valueobject": "workspace:*"
},
"publishConfig": {
"access": "public"
}
}
116 changes: 116 additions & 0 deletions src/saveslot/src/Client/Binders/HasSaveSlotsClient.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
--!strict
--[=[
@class HasSaveSlotsClient
]=]

local require = require(script.Parent.loader).load(script)

local Players = game:GetService("Players")

local Binder = require("Binder")
local HasSaveSlotsBase = require("HasSaveSlotsBase")
local HasSaveSlotsInterface = require("HasSaveSlotsInterface")
local Promise = require("Promise")
local Remoting = require("Remoting")
local SaveSlotData = require("SaveSlotData")
local ServiceBag = require("ServiceBag")

local HasSaveSlotsClient = setmetatable({}, HasSaveSlotsBase)
HasSaveSlotsClient.ClassName = "HasSaveSlotsClient"
HasSaveSlotsClient.__index = HasSaveSlotsClient

export type HasSaveSlotsClient =
typeof(setmetatable(
{} :: {
_obj: Player,
_serviceBag: ServiceBag.ServiceBag,
_remoting: any,
},
{} :: typeof({ __index = HasSaveSlotsClient })
))
& HasSaveSlotsBase.HasSaveSlotsBase

function HasSaveSlotsClient.new(player: Player, serviceBag: ServiceBag.ServiceBag): HasSaveSlotsClient
if player ~= Players.LocalPlayer then
return nil :: any
end

local self: HasSaveSlotsClient = setmetatable(HasSaveSlotsBase.new(player, serviceBag) :: any, HasSaveSlotsClient)

self._serviceBag = assert(serviceBag, "No serviceBag")

self._remoting = self._maid:Add(Remoting.Client.new(self._obj, "HasSaveSlots"))

self._maid:GiveTask(HasSaveSlotsInterface.Client:Implement(self._obj, self))

return self
end

--[=[
Returns whether the slot at the given index exists
]=]
function HasSaveSlotsClient.PromiseHasSlot(self: HasSaveSlotsClient, slotIndex: number): Promise.Promise<boolean>
return self._remoting.PromiseHasSlot:PromiseInvokeServer(slotIndex)
end

--[=[
Selects the slot at the given index
]=]
function HasSaveSlotsClient.PromiseSelectSlot(self: HasSaveSlotsClient, slotIndex: number): Promise.Promise<any>
return self._remoting.PromiseSelectSlot:PromiseInvokeServer(slotIndex)
end

--[=[
Creates a slot at the given index
]=]
function HasSaveSlotsClient.PromiseCreateSlot(
self: HasSaveSlotsClient,
slotIndex: number,
metadata: SaveSlotData.SaveSlotMetadata?
): Promise.Promise<any>
return self._remoting.PromiseCreateSlot:PromiseInvokeServer(slotIndex, metadata)
end

--[=[
Deletes the slot at the given index
]=]
function HasSaveSlotsClient.PromiseDeleteSlot(self: HasSaveSlotsClient, slotIndex: number): Promise.Promise<any>
return self._remoting.PromiseDeleteSlot:PromiseInvokeServer(slotIndex)
end

--[=[
Sets the metadata for the slot at the given index
]=]
function HasSaveSlotsClient.PromiseSetSlotMetadata(
self: HasSaveSlotsClient,
slotIndex: number,
data: SaveSlotData.SaveSlotMetadata
): Promise.Promise<any>
return self._remoting.PromiseSetSlotMetadata:PromiseInvokeServer(slotIndex, data)
end

--[=[
Gets the metadata for the slot at the given index
]=]
function HasSaveSlotsClient.PromiseGetSlotMetadata(
self: HasSaveSlotsClient,
slotIndex: number
): Promise.Promise<SaveSlotData.SaveSlotMetadata>
return self._remoting.PromiseGetSlotMetadata:PromiseInvokeServer(slotIndex)
end

--[=[
Gets the last active slot index
]=]
function HasSaveSlotsClient.PromiseLastActiveSlotIndex(self: HasSaveSlotsClient): Promise.Promise<number?>
return self._remoting.PromiseLastActiveSlotIndex:PromiseInvokeServer()
end

--[=[
Refreshes the active slot summary
]=]
function HasSaveSlotsClient.PromiseRefreshActiveSlotSummary(self: HasSaveSlotsClient): Promise.Promise<any>
return self._remoting.PromiseRefreshActiveSlotSummary:PromiseInvokeServer()
end

return Binder.new("HasSaveSlots", HasSaveSlotsClient :: any) :: Binder.Binder<HasSaveSlotsClient>
49 changes: 49 additions & 0 deletions src/saveslot/src/Client/Cmdr/SaveSlotCmdrServiceClient.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
--!strict
--[=[
@class SaveSlotCmdrServiceClient
]=]

local require = require(script.Parent.loader).load(script)

local CmdrServiceClient = require("CmdrServiceClient")
local Maid = require("Maid")
local SaveSlotCmdrUtils = require("SaveSlotCmdrUtils")
local SaveSlotDataService = require("SaveSlotDataService")
local ServiceBag = require("ServiceBag")

local SaveSlotCmdrServiceClient = {}
SaveSlotCmdrServiceClient.ServiceName = "SaveSlotCmdrServiceClient"

export type SaveSlotCmdrServiceClient = typeof(setmetatable(
{} :: {
_serviceBag: ServiceBag.ServiceBag,
_maid: Maid.Maid,
_cmdrServiceClient: any,
_saveSlotDataService: any,
},
{} :: typeof({ __index = SaveSlotCmdrServiceClient })
))

function SaveSlotCmdrServiceClient.Init(self: SaveSlotCmdrServiceClient, serviceBag: ServiceBag.ServiceBag)
assert(not (self :: any)._serviceBag, "Already initialized")
self._serviceBag = assert(serviceBag, "No serviceBag")
self._maid = Maid.new()

-- External
self._cmdrServiceClient = self._serviceBag:GetService(CmdrServiceClient)

-- Internal
self._saveSlotDataService = self._serviceBag:GetService(SaveSlotDataService)
end

function SaveSlotCmdrServiceClient.Start(self: SaveSlotCmdrServiceClient)
self._maid:GivePromise(self._cmdrServiceClient:PromiseCmdr()):Then(function(cmdr)
SaveSlotCmdrUtils.registerSlotIndexType(cmdr, self._saveSlotDataService)
end)
end

function SaveSlotCmdrServiceClient.Destroy(self: SaveSlotCmdrServiceClient): ()
self._maid:Destroy()
end

return SaveSlotCmdrServiceClient
55 changes: 55 additions & 0 deletions src/saveslot/src/Client/SaveSlotServiceClient.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
--!strict
--[=[
@class SaveSlotServiceClient
]=]

local require = require(script.Parent.loader).load(script)

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Maid = require("Maid")
local Remoting = require("Remoting")
local ServiceBag = require("ServiceBag")

local SaveSlotServiceClient = {}
SaveSlotServiceClient.ServiceName = "SaveSlotServiceClient"

export type SaveSlotServiceClient = typeof(setmetatable(
{} :: {
_serviceBag: ServiceBag.ServiceBag,
_maid: Maid.Maid,
_remoting: any,
},
{} :: typeof({ __index = SaveSlotServiceClient })
))

function SaveSlotServiceClient.Init(self: SaveSlotServiceClient, serviceBag: ServiceBag.ServiceBag)
assert(not (self :: any)._serviceBag, "Already initialized")
self._serviceBag = assert(serviceBag, "No serviceBag")
self._maid = Maid.new()

-- Internal
self._serviceBag:GetService(require("SaveSlotCmdrServiceClient"))
self._serviceBag:GetService(require("SaveSlotDataService"))

-- Binders
self._serviceBag:GetService(require("HasSaveSlotsClient"))

self._remoting = self._maid:Add(Remoting.Client.new(ReplicatedStorage, "SaveSlotService"))
end

--[=[
Returns whether explicit slot selection is required
]=]
function SaveSlotServiceClient.GetExplicitSelectionRequiredAsync(self: SaveSlotServiceClient): boolean
return self._remoting.GetExplicitSelectionRequired:InvokeServer()
end

--[=[
Destroys the service
]=]
function SaveSlotServiceClient.Destroy(self: SaveSlotServiceClient): ()
self._maid:Destroy()
end

return SaveSlotServiceClient
Loading
Loading