interface case, acrylic ui, swap to make, lint

This commit is contained in:
Reid 2023-08-15 20:18:59 -07:00
parent f5584a9b0c
commit a5bc77030a
24 changed files with 353 additions and 92 deletions

View file

@ -6,7 +6,7 @@ import { Host } from "ReplicatedStorage/hosts"
import { tags } from "./boundTags"
import { Model } from "./components"
import { start as startReplication, stop as stopReplication } from "./replication"
import { clientState, serverState } from "./state"
import { ClientState, ServerState } from "./state"
import { start as startSystems, stop as stopSystems } from "./systems"
import { start as startTags, stop as stopTags } from "./tags"
@ -45,13 +45,13 @@ export function start<S extends object>(host: Host, state: S): [World, S] {
})
if (host === Host.All || host === Host.Server) {
const ServerState = state as serverState
const ServerState = state as ServerState
startTags(world, tags, ServerState)
}
if (host === Host.All || host === Host.Client) {
const ClientState = state as clientState
const ClientState = state as ClientState
startReplication(world, ClientState)

View file

@ -1,7 +1,7 @@
import { AnyEntity, World } from "@rbxts/matter"
import { waitForEvent } from "ReplicatedStorage/remotes"
import * as Components from "./components"
import { clientState } from "./state"
import { ClientState } from "./state"
type ComponentNames = keyof typeof Components
type ComponentConstructors = (typeof Components)[ComponentNames]
@ -14,7 +14,7 @@ let connection: RBXScriptConnection | undefined
* @param world - The world to replicate components in
* @param client - The client state for the ECS
*/
export function start(world: World, client: clientState): void {
export function start(world: World, client: ClientState): void {
if (connection) return
const replicationEvent = waitForEvent("EcsReplication")

View file

@ -7,7 +7,7 @@ import { InputKind } from "ReplicatedStorage/inputKind"
/**
* The client ECS state.
*/
export class clientState {
export class ClientState {
constructor(
player: Player,
character: CharacterRigR6,
@ -41,7 +41,7 @@ export class clientState {
/**
* The server ECS state.
*/
export class serverState {
export class ServerState {
constructor(
logger: Logger
) {
@ -54,4 +54,4 @@ export class serverState {
/**
* The shared ECS state.
*/
export type sharedState = serverState & clientState
export type SharedState = ServerState & ClientState

View file

@ -1,6 +1,6 @@
import { World, useEvent } from "@rbxts/matter"
import { StarterGui } from "@rbxts/services"
import { clientState } from "ReplicatedStorage/ecs/state"
import { ClientState } from "ReplicatedStorage/ecs/state"
import { getEvent } from "ReplicatedStorage/remotes"
const resetButtonCallback = new Instance("BindableEvent")
@ -8,7 +8,7 @@ StarterGui.SetCore("ResetButtonCallback", resetButtonCallback)
getEvent("resetButton")
function customReset(_: World, _client: clientState): void {
function customReset(_: World, _client: ClientState): void {
const resetButtonEvent = getEvent("resetButton")
for (const [,] of useEvent(resetButtonCallback, "Event")) {
resetButtonEvent.FireServer()

View file

@ -1,10 +1,10 @@
import { useDeltaTime, useEvent, useThrottle, World } from "@rbxts/matter"
import { UserInputService } from "@rbxts/services"
import { clientState } from "ReplicatedStorage/ecs/state"
import { ClientState } from "ReplicatedStorage/ecs/state"
import { InputKind } from "ReplicatedStorage/inputKind"
let holdDuration = 0
function inputMapper(_: World, client: clientState): void {
function inputMapper(_: World, client: ClientState): void {
for (const [, input, gpe] of useEvent(UserInputService, "InputBegan")) {
if (gpe) return undefined
if (input.KeyCode !== Enum.KeyCode.Unknown) {

View file

@ -1,8 +1,8 @@
import { World } from "@rbxts/matter"
import { match } from "@rbxts/variant"
import { clientState } from "ReplicatedStorage/ecs/state"
import { ClientState } from "ReplicatedStorage/ecs/state"
function sprint(_: World, client: clientState): void {
function sprint(_: World, client: ClientState): void {
if (client.lastProcessedCommand !== undefined) {
match(client.lastProcessedCommand, {
KeyDown: ({ key }) => {

View file

@ -2,7 +2,7 @@ import { AnyEntity, Component, World } from "@rbxts/matter"
import { CollectionService } from "@rbxts/services"
import { getIdAttribute } from "ReplicatedStorage/idAttribute"
import { Model, Transform } from "./components"
import { serverState } from "./state"
import { ServerState } from "./state"
export type ComponentConstructor<T extends object> = () => Component<T>
@ -17,7 +17,7 @@ const connections: RBXScriptConnection[] = []
export function start(
world: World,
bound: ReadonlyMap<string, ComponentConstructor<object>>,
server: serverState
server: ServerState
): void {
function spawnBound<T extends object>(
instance: Instance,

View file

@ -1,4 +0,0 @@
import { UseProducerHook, useProducer } from "@rbxts/roact-reflex"
import { rootProducer } from "../producer"
export const useRootProducer: UseProducerHook<rootProducer> = useProducer

View file

@ -1,9 +0,0 @@
import { InferDispatchers, InferState, combineProducers, loggerMiddleware } from "@rbxts/reflex"
export type rootProducer = typeof producer
export type rootState = InferState<rootProducer>
export type rootDispatchers = InferDispatchers<rootProducer>
export const producer = combineProducers({
}).applyMiddleware(loggerMiddleware)

View file

@ -0,0 +1,77 @@
import Make from "@rbxts/make"
export type AcrylicInstance = Model & {
Horizontal: Part & { Mesh: SpecialMesh }
Vertical: Part & { Mesh: SpecialMesh }
TopLeft: Part & { Mesh: SpecialMesh }
TopRight: Part & { Mesh: SpecialMesh }
BottomLeft: Part & { Mesh: SpecialMesh }
BottomRight: Part & { Mesh: SpecialMesh }
}
const fill = {
Color: new Color3(0, 0, 0),
Material: Enum.Material.Glass,
Size: new Vector3(1, 1, 0),
Anchored: true,
CanCollide: false,
Locked: true,
CastShadow: false,
Transparency: 0.999
}
const corner = {
Color: new Color3(0, 0, 0),
Material: Enum.Material.Glass,
Size: new Vector3(0, 1, 1),
Anchored: true,
CanCollide: false,
Locked: true,
CastShadow: false,
Transparency: 0.999
}
export const acrylicInstance = Make("Model", {
Children: [
Make("Part", {
Name: "Horizontal",
Children: [
Make("SpecialMesh", {
MeshType: Enum.MeshType.Brick,
Offset: new Vector3(0, 0, -0.000001)
})
],
...fill
}),
Make("Part", {
Name: "Vertical",
Children: [
Make("SpecialMesh", {
MeshType: Enum.MeshType.Brick,
Offset: new Vector3(0, 0, 0.000001)
})
],
...fill
}),
Make("Part", {
Name: "TopRight",
Children: [Make("SpecialMesh", { MeshType: Enum.MeshType.Cylinder })],
...corner
}),
Make("Part", {
Name: "TopLeft",
Children: [Make("SpecialMesh", { MeshType: Enum.MeshType.Cylinder })],
...corner
}),
Make("Part", {
Name: "BottomRight",
Children: [Make("SpecialMesh", { MeshType: Enum.MeshType.Cylinder })],
...corner
}),
Make("Part", {
Name: "BottomLeft",
Children: [Make("SpecialMesh", { MeshType: Enum.MeshType.Cylinder })],
...corner
})
]
}) as AcrylicInstance

View file

@ -0,0 +1,165 @@
import Roact from "@rbxts/roact"
import { useEffect, useCallback, useMemo, useMutable } from "@rbxts/roact-hooked"
import { acrylicInstance } from "./acrylicInstance"
import { Lighting, Workspace } from "@rbxts/services"
import Make from "@rbxts/make"
const cylinderAngleOffset = CFrame.Angles(0, math.rad(90), 0)
function viewportPointToWorld(location: Vector2, distance: number): Vector3 {
const unitRay = Workspace.CurrentCamera!.ScreenPointToRay(location.X, location.Y)
return unitRay.Origin.add(unitRay.Direction.mul(distance))
}
function map(n: number, min0: number, max0: number, min1: number, max1: number): number {
return min1 + ((n - min0) * (max1 - min1)) / (max0 - min0)
}
function getOffset(): number {
return map(Workspace.CurrentCamera!.ViewportSize.Y, 0, 2560, 8, 56)
}
const DOFEffect = Make("DepthOfFieldEffect", {
FarIntensity: 0,
InFocusRadius: 0.1,
NearIntensity: 1
})
DOFEffect.Parent = Lighting
interface acrylicProps extends Roact.JsxInstanceProperties<Frame> {
radius: number
distance: number
Event?: Roact.JsxInstanceEvents<Frame>
Change?: Roact.JsxInstanceChangeEvents<Frame>
}
function acrylic(props: acrylicProps): Roact.Element {
const { radius, distance } = props
const spreadableProps = { ...props } as Partial<acrylicProps>
delete spreadableProps.radius
delete spreadableProps.distance
const frameInfo = useMutable({
topleft2d: new Vector2(),
topright2d: new Vector2(),
bottomright2d: new Vector2(),
topleftradius2d: new Vector2()
})
const acrylic = useMemo(() => {
const clone = acrylicInstance.Clone()
clone.Parent = Workspace
return clone
}, [])
useEffect(() => {
return () => acrylic.Destroy()
}, [])
const updateFrameInfo = useCallback(
(size: Vector2, position: Vector2) => {
const topleftRaw = position.sub(size.div(2))
const info = frameInfo.current
info.topleft2d = new Vector2(math.ceil(topleftRaw.X), math.ceil(topleftRaw.Y))
info.topright2d = info.topleft2d.add(new Vector2(size.X, 0))
info.bottomright2d = info.topleft2d.add(size)
info.topleftradius2d = info.topleft2d.add(new Vector2(radius, 0))
},
[distance, radius]
)
const updateInstance = useCallback(() => {
const { topleft2d, topright2d, bottomright2d, topleftradius2d } = frameInfo.current
const topleft = viewportPointToWorld(topleft2d, distance)
const topright = viewportPointToWorld(topright2d, distance)
const bottomright = viewportPointToWorld(bottomright2d, distance)
const topleftradius = viewportPointToWorld(topleftradius2d, distance)
const cornerRadius = topleftradius.sub(topleft).Magnitude
const width = topright.sub(topleft).Magnitude
const height = topright.sub(bottomright).Magnitude
const center = CFrame.fromMatrix(
topleft.add(bottomright).div(2),
Workspace.CurrentCamera!.CFrame.XVector,
Workspace.CurrentCamera!.CFrame.YVector,
Workspace.CurrentCamera!.CFrame.ZVector
)
if (radius !== undefined && radius > 0) {
acrylic.Horizontal.CFrame = center
acrylic.Horizontal.Mesh.Scale = new Vector3(width - cornerRadius * 2, height, 0)
acrylic.Vertical.CFrame = center
acrylic.Vertical.Mesh.Scale = new Vector3(width, height - cornerRadius * 2, 0)
} else {
acrylic.Horizontal.CFrame = center
acrylic.Horizontal.Mesh.Scale = new Vector3(width, height, 0)
}
if (radius !== undefined && radius > 0) {
acrylic.TopLeft.CFrame = center
.mul(new CFrame(-width / 2 + cornerRadius, height / 2 - cornerRadius, 0))
.mul(cylinderAngleOffset)
acrylic.TopLeft.Mesh.Scale = new Vector3(0, cornerRadius * 2, cornerRadius * 2)
acrylic.TopRight.CFrame = center
.mul(new CFrame(width / 2 - cornerRadius, height / 2 - cornerRadius, 0))
.mul(cylinderAngleOffset)
acrylic.TopRight.Mesh.Scale = new Vector3(0, cornerRadius * 2, cornerRadius * 2)
acrylic.BottomLeft.CFrame = center
.mul(new CFrame(-width / 2 + cornerRadius, -height / 2 + cornerRadius, 0))
.mul(cylinderAngleOffset)
acrylic.BottomLeft.Mesh.Scale = new Vector3(0, cornerRadius * 2, cornerRadius * 2)
acrylic.BottomRight.CFrame = center
.mul(new CFrame(width / 2 - cornerRadius, -height / 2 + cornerRadius, 0))
.mul(cylinderAngleOffset)
acrylic.BottomRight.Mesh.Scale = new Vector3(0, cornerRadius * 2, cornerRadius * 2)
}
}, [radius, distance])
useEffect(() => {
updateInstance()
const posHandle = Workspace.CurrentCamera!.GetPropertyChangedSignal("CFrame").Connect(updateInstance)
const fovHandle = Workspace.CurrentCamera!.GetPropertyChangedSignal("FieldOfView").Connect(updateInstance)
const viewportHandle = Workspace.CurrentCamera!.GetPropertyChangedSignal("ViewportSize").Connect(updateInstance)
return () => {
posHandle.Disconnect()
fovHandle.Disconnect()
viewportHandle.Disconnect()
}
}, [updateInstance])
return (
<frame
Change={{
AbsoluteSize: (rbx): void => {
const blurOffset = getOffset()
const size = rbx.AbsoluteSize.sub(new Vector2(blurOffset, blurOffset))
const position = rbx.AbsolutePosition.add(rbx.AbsoluteSize.div(2))
updateFrameInfo(size, position)
task.spawn(updateInstance)
},
AbsolutePosition: (rbx): void => {
const blurOffset = getOffset()
const size = rbx.AbsoluteSize.sub(new Vector2(blurOffset, blurOffset))
const position = rbx.AbsolutePosition.add(rbx.AbsoluteSize.div(2))
updateFrameInfo(size, position)
task.spawn(updateInstance)
}
}}
Size={new UDim2(1, 0, 1, 0)}
BackgroundTransparency={1}
/>
)
}
export default acrylic

View file

@ -1,4 +1,3 @@
import Hooks from "@rbxts/roact-hooked"
import Roact from "@rbxts/roact"
interface paddingProps extends Roact.JsxInstanceProperties<UIPadding> {