diff --git a/src/client/ClientMessenger.ts b/src/client/ClientMessenger.ts index b29aed5..a4ded34 100644 --- a/src/client/ClientMessenger.ts +++ b/src/client/ClientMessenger.ts @@ -3,7 +3,7 @@ export function bindToOutput(functionToBind: Callback) { assert(Output?.IsA("RemoteEvent"), 'Remote event "Input" is of incorrect class or nil'); Output.OnClientEvent.Connect(functionToBind); } -export function messageServer(messageType: clientMessageType, messageContent?: string) { +export function messageServer(messageType: clientMessageType, messageContent?: unknown) { assert(Input?.IsA("RemoteEvent"), 'Remote event "Output" is of incorrect class or nil'); Input.FireServer(messageType, messageContent); } diff --git a/src/client/EffectMaker.ts b/src/client/EffectMaker.ts new file mode 100644 index 0000000..629404e --- /dev/null +++ b/src/client/EffectMaker.ts @@ -0,0 +1 @@ +export function kablooey() {} diff --git a/src/client/GuiHandler.ts b/src/client/GuiHandler.ts index 2a3ec61..d445df4 100644 --- a/src/client/GuiHandler.ts +++ b/src/client/GuiHandler.ts @@ -50,7 +50,7 @@ interface guiEntry { color?: Color3; transparency: number; pages: guiElementEntry[][]; - closeFunction: Callback; + closeFunction: (baseFrame: Frame) => void; } interface guiTable { @@ -64,13 +64,15 @@ const stylesTable: guiStyleTable = { BackgroundColor: Color3.fromRGB(0, 0, 0), }, TextLabel: { - TextColor: Color3.fromRGB(255, 0, 0), - Font: Enum.Font.AmaticSC, + TextColor: Color3.fromRGB(255, 255, 255), + Font: Enum.Font.Ubuntu, TextScaled: true, }, TextButton: { - BackgroundTransparency: 0.125, - BackgroundColor: Color3.fromRGB(255, 0, 255), + BackgroundTransparency: 0.9, + BackgroundColor: Color3.fromRGB(255, 255, 255), + TextColor: Color3.fromRGB(255, 255, 255), + Font: Enum.Font.Ubuntu, TextScaled: true, }, }, @@ -86,6 +88,7 @@ const guiTable: guiTable = { Style: stylesTable["placeholder"], Position: new UDim2(0, 0, 0.175, 0), Size: new UDim2(1, 0, 0.15, 0), + Font: Enum.Font.Garamond, Text: "Placeholder", }, { @@ -112,8 +115,14 @@ const guiTable: guiTable = { }, ], ], - closeFunction: function (baseFrame) { - tweenService.Create(baseFrame, new TweenInfo(0.5), { Position: new UDim2(1, 0, 0, 0) }).Play(); + closeFunction: function (this: void, baseFrame: Frame) { + print(baseFrame); + tweenService + .Create(baseFrame, new TweenInfo(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), { + Position: new UDim2(1, 0, 0, 0), + }) + .Play(); + wait(1); }, }, }; @@ -143,6 +152,7 @@ function configureTextElement( } function drawGuiElement(elementEntry: guiElementEntry, objectsToReturn: [TextButton | ImageButton, onClickEntry][]) { + print("fortnite"); const elementType = elementEntry["Type"]; const elementStyle = elementEntry["Style"][elementType]; const elementStyleDefault = elementEntry["Style"].default; @@ -168,22 +178,25 @@ function drawGuiElement(elementEntry: guiElementEntry, objectsToReturn: [TextBut assert( classIs(guiElement, "TextButton") || classIs(guiElement, "ImageButton"), 'Property "OnClick" should not exist on non-button instance!', - ); + ); // Temporary? objectsToReturn.push([guiElement, elementEntry.onClick]); } return guiElement; } export function drawGui(PLAYERGUI: PlayerGui, guiName: "MainMenu") { + print("opening gui"); const objectsToReturn: [TextButton | ImageButton, onClickEntry][] = []; const guiEntry = guiTable[guiName]; assert(guiEntry, 'Error in Gui Handler: Gui "' + guiName + " not found!"); // Actual Gui creation const screenGui = new Instance("ScreenGui"); screenGui.Name = guiName; + screenGui.IgnoreGuiInset = true; screenGui.ResetOnSpawn = false; // ? screenGui.Parent = PLAYERGUI; const baseFrame = new Instance("Frame"); + baseFrame.Name = "baseFrame"; baseFrame.BackgroundTransparency = guiEntry.transparency; baseFrame.BackgroundColor3 = guiEntry.color || Color3.fromRGB(0, 0, 0); baseFrame.Position = guiEntry.position || new UDim2(0, 0, 0, 0); @@ -192,12 +205,16 @@ export function drawGui(PLAYERGUI: PlayerGui, guiName: "MainMenu") { const guiElement = drawGuiElement(guiElementEntry, objectsToReturn); guiElement.Parent = baseFrame; } + baseFrame.Parent = screenGui; screenGui.Parent = PLAYERGUI; return objectsToReturn; } export function closeGui(PLAYERGUI: PlayerGui, guiName: "MainMenu") { const screenGui = PLAYERGUI.WaitForChild(guiName, 1); - assert(screenGui, 'ScreenGui"' + guiName + '" does not exist!'); - screenGui; + assert(screenGui, 'ScreenGui "' + guiName + '" does not exist!'); + const baseFrame = screenGui.WaitForChild("baseFrame", 1); + assert(baseFrame && classIs(baseFrame, "Frame"), 'Baseframe of "' + guiName + '" does not exist!'); + const closeFunction = guiTable[guiName].closeFunction(baseFrame); + screenGui.Destroy(); } diff --git a/src/client/ModesLocal.ts b/src/client/ModesLocal.ts new file mode 100644 index 0000000..cd02482 --- /dev/null +++ b/src/client/ModesLocal.ts @@ -0,0 +1,5 @@ +export const gamer: { [modeId: string]: modeLocal } = { + ["Flawless"]: { + //aura: [[["Ball"]]], // Will come back to this later + }, +}; diff --git a/src/client/init.client.ts b/src/client/init.client.ts index 3c78a76..02df7d1 100644 --- a/src/client/init.client.ts +++ b/src/client/init.client.ts @@ -1,32 +1,58 @@ // "init": The local script. This script doesn't have to account for any other players. const Players = game.GetService("Players"); const UserInputService = game.GetService("UserInputService"); +const Workspace = game.GetService("Workspace"); import { bindToOutput, messageServer } from "./ClientMessenger"; import { handleGuiInput, drawGui, closeGui } from "./GuiHandler"; const LOCALPLAYER = Players.LocalPlayer; const PLAYERGUI = LOCALPLAYER.WaitForChild("PlayerGui", 1) as PlayerGui; -assert(PLAYERGUI && classIs(PLAYERGUI, "PlayerGui"), 'PlayerGui of "' + LOCALPLAYER.Name + '"does not exist! (HOW???)'); +assert( + PLAYERGUI && classIs(PLAYERGUI, "PlayerGui"), + 'PlayerGui of "' + LOCALPLAYER.DisplayName + '"does not exist! (HOW???)', +); +const CAMERA = Workspace.CurrentCamera as Camera; +assert(CAMERA, 'Camera of "' + LOCALPLAYER.DisplayName + '"does not exist! (HOW???)'); let inMainMenu = true; function openMainMenu(playerGui: PlayerGui) { - messageServer("Placeholder", "OpeningMainMenu"); // > Server should check if there are entities to clean up + messageServer("placeholder", "OpeningMainMenu"); // > Server should check if there are entities to clean up + new messagetype? const mainMenuButtons = drawGui(playerGui, "MainMenu"); for (const mainMenuButton of mainMenuButtons) { mainMenuButton[0].Activated.Connect(function () { handleGuiInput(messageServer, mainMenuButton[1][0], mainMenuButton[1][1]); - }); + }); // + Good ETC extension - Add support for other controller types } - inMainMenu = true; } + +const hitParams = new RaycastParams(); +//hitParams.FilterDescendantsInstances = {efFolder,Plr.Character} +//hitParams.FilterType = Enum.RaycastFilterType.Blacklist; +function getMouseLocation(): [Vector3, Vector3, Instance | undefined] { + //hitParams.FilterDescendantsInstances = {efFolder,Plr.Character} + const mouseLocation = UserInputService.GetMouseLocation(); + const unitRay = CAMERA.ViewportPointToRay(mouseLocation.X, mouseLocation.Y); + const cast = Workspace.Raycast(unitRay.Origin, unitRay.Direction.mul(1000), hitParams); + if (cast) { + return [cast.Position, cast.Normal, cast.Instance]; + } else { + return [unitRay.Origin.add(unitRay.Direction.mul(1000)), new Vector3(0, 0, 0), undefined]; + } +} + function handleInput(input: InputObject, otherInteraction: boolean) { + let mousePosition: Vector3, mouseNormal: Vector3, mouseInstance: Instance | undefined; + [mousePosition, mouseNormal, mouseInstance] = getMouseLocation(); // eslint-disable-line prefer-const if (input.UserInputType === Enum.UserInputType.MouseButton1) { + messageServer("move", mousePosition); } } function handleOutput(messageType: unknown, messageContent: unknown) { if (messageType === "init") { openMainMenu(PLAYERGUI); + inMainMenu = true; } else if (messageType === "enterGame") { closeGui(PLAYERGUI, "MainMenu"); + inMainMenu = false; } } // Action phase diff --git a/src/server/Hitboxer.ts b/src/server/Hitboxer.ts new file mode 100644 index 0000000..d063bc1 --- /dev/null +++ b/src/server/Hitboxer.ts @@ -0,0 +1,2 @@ +// Later +export function hitBox() {} diff --git a/src/server/main.server.ts b/src/server/main.server.ts index 2b43a92..0b51891 100644 --- a/src/server/main.server.ts +++ b/src/server/main.server.ts @@ -1,7 +1,7 @@ // "main": This is the core of reality. It serves as the highest-level abstraction. // + Prevent this from coupling with the entity manager, if possible const Players = game.GetService("Players"); -import { makeEntity } from "shared/EntityManager"; +import { makeEntity, moveEntity } from "shared/EntityManager"; import { initPlayer, deinitPlayer, loadInPlayer, teleportPlayer } from "shared/PlayerManager"; import { bindToInput, messageClient, messageAllClients } from "./ServerMessenger"; const playerStorage: (playerStorageEntry | undefined)[] = []; @@ -21,13 +21,16 @@ function handleInput(player: Player, messageType: unknown, messageContent: unkno entityStorage[player.UserId] = loadInPlayer(player); messageClient(player, "enterGame"); } catch (thrownError) { - const errorMessage = 'Error when creating entity of "' + player.DisplayName + '": ' + thrownError; - warn(errorMessage); - messageClient(player, "promptError", errorMessage); + if (typeIs(thrownError, "string")) { + const errorMessage: string = + 'Error when creating entity of "' + player.DisplayName + '": ' + thrownError; + warn(errorMessage); + messageClient(player, "promptError", errorMessage); + } } - } else if (messageType === "placeholder") { - const entity = entityStorage[player.UserId]; - if (entity && entity.puppet) { + } else if (messageType === "move") { + if (typeIs(messageContent, "Vector3")) { + moveEntity(entityStorage[player.UserId], messageContent); } } } diff --git a/src/services.d.ts b/src/services.d.ts index 6db54b3..4cf32fc 100644 --- a/src/services.d.ts +++ b/src/services.d.ts @@ -1,6 +1,7 @@ type puppetEntry = ["Character", Player] | ["Placeholder", "Placeholder"]; +type bodyPart = "root" | "torso" | "head" | "leftArm" | "rightArm" | "leftLeg" | "rightLeg"; type serverMessageType = "init" | "promptError" | "enterGame"; -type clientMessageType = "Placeholder"; +type clientMessageType = "move" | "placeholder"; interface saveDataEntry { placeholder: string; @@ -12,6 +13,7 @@ interface playerStorageEntry { entity?: entity; } interface puppet { + entry: puppetEntry; model: Model; rootPart: Part; //placeholder: (x: string) => string; // + "Puppet string" functions will (not?) go here @@ -27,6 +29,14 @@ interface event { timeout?: number; // A timeout for the event; passes a lose condition if there are other completion requirements that have not been satisfied } +type meshType = "Ball"; +type effectState = [CFrame, Vector3, Color3, number]; // The number is transparency +type effectEntry = [meshType, EnumItem, effectState[]]; // The enumitem is material + +interface modeLocal { + aura?: [effectEntry, bodyPart?, number?][]; // effect, part it is attached to (default root), how many times it should be called per frame (default 1) +} + /*interface hookInEntry { name: string; guiObject: GuiObject; diff --git a/src/shared/EntityManager.ts b/src/shared/EntityManager.ts index 9b0ea1f..e414b8e 100644 --- a/src/shared/EntityManager.ts +++ b/src/shared/EntityManager.ts @@ -1,6 +1,6 @@ // "EntityManager": Create entities objects and deck them out with functions to use. // + Functions are here, as to avoid storing unecessary data in the server store. -import { makePuppet } from "./Puppetmaster"; +import { makePuppet, movePuppet } from "./Puppetmaster"; export function makeEntity(puppetEntry: puppetEntry) { const newEntity: entity = { baseStats: [0, 0, 0, 0], @@ -9,3 +9,10 @@ export function makeEntity(puppetEntry: puppetEntry) { }; return newEntity; } + +// This exists because the main server should never see the puppets, but it is a bit weird +export function moveEntity(entity: entity | undefined, location: Vector3) { + if (entity) { + entity.puppet = movePuppet(entity.puppet, location); + } +} diff --git a/src/shared/Puppetmaster.ts b/src/shared/Puppetmaster.ts index 08f13bd..b68a755 100644 --- a/src/shared/Puppetmaster.ts +++ b/src/shared/Puppetmaster.ts @@ -9,6 +9,7 @@ export function makePuppet(puppetEntry: puppetEntry) { if (puppetEntry[0] === "Character") { const model: [Model, Part] = puppetLibraries[puppetEntry[0]].makeModel(puppetEntry[1]); return { + entry: puppetEntry, model: model[0], rootPart: model[1], }; @@ -16,3 +17,22 @@ export function makePuppet(puppetEntry: puppetEntry) { throw 'Invalid puppet type "' + puppetEntry[0] + '"!'; } } + +function verifyPuppetExistence(puppet: puppet) { + if (puppet.rootPart.Parent) { + // Placeholder; puppet integrity will include other body parts + return puppet; + } else { + print("No puppet!"); + return makePuppet(puppet.entry); + } +} + +export function movePuppet(puppet: puppet, location: Vector3) { + print("executing puppet move"); + puppet = verifyPuppetExistence(puppet); //const newPuppet = verifyPuppetExistence(puppet); + //puppet.rootPart = newPuppet.rootPart; + //puppet.model = newPuppet.model; + puppet.rootPart.CFrame = new CFrame(location); + return puppet; +}