Moved some interfaces out of services to decouple
+ More OOP changes on the server side
This commit is contained in:
parent
47bde9f3ce
commit
79202b9034
11 changed files with 260 additions and 134 deletions
|
@ -1,5 +1,5 @@
|
|||
import { Input, Output } from "shared/Remotes";
|
||||
export function bindToOutput(functionToBind: Callback) {
|
||||
export function bindToServerMessage(functionToBind: Callback) {
|
||||
assert(Output?.IsA("RemoteEvent"), 'Remote event "Input" is of incorrect class or nil');
|
||||
Output.OnClientEvent.Connect(functionToBind);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ interface effectHandler extends effectMaker, effectRunner {
|
|||
}
|
||||
|
||||
export function makeEffectHandler(effectFolder: Folder) {
|
||||
const effectHandler: effectHandler = {
|
||||
return {
|
||||
meshPartEffect: function(meshPart: MeshPart, material: Enum.Material, effectKeypoints: effectKeypoint[], priority?: number) {
|
||||
const effectMeshPart = meshPart.Clone();
|
||||
effectMeshPart.Material = material;
|
||||
|
@ -102,8 +102,7 @@ export function makeEffectHandler(effectFolder: Folder) {
|
|||
|
||||
EFFECT_FOLDER: effectFolder,
|
||||
effectsToRun: [],
|
||||
}
|
||||
return effectHandler;
|
||||
} as effectHandler;
|
||||
}
|
||||
/*
|
||||
local function horseEffModule(o,typ,a1,a2,a3,a4,a5,a6,a7)
|
||||
|
|
96
src/client/InputHandler.ts
Normal file
96
src/client/InputHandler.ts
Normal file
|
@ -0,0 +1,96 @@
|
|||
const Players = game.GetService("Players");
|
||||
const UserInputService = game.GetService("UserInputService");
|
||||
const ContextActionService = game.GetService("ContextActionService");
|
||||
const Workspace = game.GetService("Workspace");
|
||||
const CAMERA = Workspace.CurrentCamera as Camera;
|
||||
assert(CAMERA, 'Camera of "' + Players.LocalPlayer.DisplayName + '"does not exist! (HOW???)');
|
||||
|
||||
export type inputBindings = {
|
||||
[input in keyof controlBindings]?: [((argument1?: unknown, argument2?: unknown) => void), unknown, unknown];
|
||||
};
|
||||
|
||||
export interface inputBinder {
|
||||
assignControlBindings: (controlBindings: controlBindings) => void;
|
||||
assignInputBindings: (inputBindings: inputBindings) => void;
|
||||
removeInputBindings: (inputBindings: inputBindings) => void;
|
||||
}
|
||||
|
||||
interface inputHandler extends inputBinder {
|
||||
controlHandler: (actionName: string, state: Enum.UserInputState, inputObject: InputObject) => void;
|
||||
controlBindings?: controlBindings
|
||||
boundInputs: inputBindings
|
||||
storedInput?: string // + compound inputs
|
||||
}
|
||||
|
||||
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 isValidInput(controlBindings: controlBindings, value: string): value is keyof controlBindings {
|
||||
return value in controlBindings; // uh oh
|
||||
}
|
||||
//function(actionName: string, state: Enum.UserInputState, inputObject: InputObject) {
|
||||
// inputParameters[0](inputParameters[1])
|
||||
//}
|
||||
|
||||
export function makeInputHandler() {
|
||||
const t: inputHandler = {//return {
|
||||
assignControlBindings: function(controlBindings: controlBindings) {
|
||||
this.controlBindings = controlBindings // WOW!!!!!
|
||||
},
|
||||
assignInputBindings: function(inputBindings: inputBindings) {
|
||||
const controlBindings = this.controlBindings;
|
||||
if (controlBindings) {
|
||||
for (let input in inputBindings) {
|
||||
if (isValidInput(controlBindings, input)) {
|
||||
// + Check for this.boundInputs[input]
|
||||
const inputParameters = inputBindings[input]
|
||||
if (inputParameters) {
|
||||
this.boundInputs[input] = inputParameters;
|
||||
const controlArray = controlBindings[input];
|
||||
for (const control of controlArray) {
|
||||
ContextActionService.BindAction(input, this.controlHandler, false, control)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
removeInputBindings: function(inputBindings: inputBindings) {},
|
||||
controlHandler: function(actionName: string, state: Enum.UserInputState, inputObject: InputObject) {
|
||||
const controlBindings = this.controlBindings;
|
||||
if (controlBindings) {
|
||||
if (isValidInput(controlBindings, actionName)) {
|
||||
const inputParameters = this.boundInputs[actionName]
|
||||
if (inputParameters) {
|
||||
inputParameters[0](inputParameters[1], inputParameters[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
boundInputs: {}
|
||||
} //as inputHandler;
|
||||
}
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// UserInputService.InputBegan.Connect(handleInput);
|
|
@ -1,9 +1,7 @@
|
|||
// "init": The local script. This script doesn't have to account for any other players.
|
||||
// "init": The main client-side thread.
|
||||
const Players = game.GetService("Players");
|
||||
const UserInputService = game.GetService("UserInputService");
|
||||
const RunService = game.GetService("RunService");
|
||||
const Workspace = game.GetService("Workspace");
|
||||
import { bindToOutput, messageServer } from "./ClientMessenger";
|
||||
import { bindToServerMessage, messageServer } from "./ClientMessenger";
|
||||
import { handleGuiInput, drawGui, closeGui } from "./GuiHandler";
|
||||
import { makeEffectHandler, effectRunner } from "./EffectMaker";
|
||||
const LOCALPLAYER = Players.LocalPlayer;
|
||||
|
@ -12,8 +10,6 @@ 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) {
|
||||
|
@ -26,29 +22,7 @@ function openMainMenu(playerGui: PlayerGui) {
|
|||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
function handleServerMessage(messageType: unknown, messageContent: unknown) {
|
||||
if (messageType === "init") {
|
||||
openMainMenu(PLAYERGUI);
|
||||
inMainMenu = true;
|
||||
|
@ -57,12 +31,12 @@ function handleOutput(messageType: unknown, messageContent: unknown) {
|
|||
inMainMenu = false;
|
||||
}
|
||||
}
|
||||
// Action phase
|
||||
UserInputService.InputBegan.Connect(handleInput);
|
||||
bindToOutput(handleOutput);
|
||||
// Bind functions
|
||||
|
||||
bindToServerMessage(handleServerMessage);
|
||||
|
||||
const effectRunners: effectRunner[] = [];
|
||||
// Put stuff in the effectRunners table
|
||||
// + Put stuff in the effectRunners table
|
||||
RunService.RenderStepped.Connect(function(deltaTime) {
|
||||
effectRunners.forEach(effectRunner => {
|
||||
effectRunner.runEffects(deltaTime)
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import { Input, Output } from "shared/Remotes";
|
||||
export function bindToInput(functionToBind: Callback) {
|
||||
export function bindToClientMessage(functionToBind: Callback) {
|
||||
assert(Input?.IsA("RemoteEvent"), 'Remote event "Input" is of incorrect class or nil');
|
||||
Input.OnServerEvent.Connect(functionToBind);
|
||||
}
|
||||
export function messageClient(client: Player, messageType: serverMessageType, messageContent?: string) {
|
||||
export function messageClient(client: Player, messageType: string, messageContent?: string) {
|
||||
assert(Output?.IsA("RemoteEvent"), 'Remote event "Output" is of incorrect class or nil');
|
||||
Output.FireClient(client, messageType, messageContent);
|
||||
}
|
||||
export function messageAllClients(messageType: serverMessageType, messageContent?: string) {
|
||||
export function messageAllClients(messageType: string, messageContent?: string) {
|
||||
assert(Output?.IsA("RemoteEvent"), 'Remote event "Output" is of incorrect class or nil');
|
||||
Output.FireAllClients(messageType, messageContent);
|
||||
}
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
// "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, moveEntity } from "shared/EntityManager";
|
||||
import { initPlayer, deinitPlayer, loadInPlayer, teleportPlayer } from "shared/PlayerManager";
|
||||
import { bindToInput, messageClient, messageAllClients } from "./ServerMessenger";
|
||||
const playerStorage: (playerStorageEntry | undefined)[] = [];
|
||||
const entityStorage: entity[] = [];
|
||||
import { makePlayerStorage, playerStorage, storedPlayer } from "shared/PlayerManager";
|
||||
import { bindToClientMessage, messageClient, messageAllClients } from "./ServerMessenger";
|
||||
const playerStorage: playerStorage = makePlayerStorage();
|
||||
|
||||
function addPlayer(player: Player) {
|
||||
playerStorage[player.UserId] = initPlayer(player);
|
||||
playerStorage.initPlayer(player);
|
||||
messageClient(player, "init", "idk");
|
||||
}
|
||||
function removePlayer(player: Player) {
|
||||
playerStorage[player.UserId] = deinitPlayer(playerStorage[player.UserId], player);
|
||||
playerStorage.deinitPlayer(player);
|
||||
}
|
||||
// Handling input is a complicated process that requires passing a large variety of data to a large variety of places, so it's staying here for now
|
||||
function handleInput(player: Player, messageType: unknown, messageContent: unknown) {
|
||||
function handleClientMessage(player: Player, messageType: unknown, messageContent: unknown) {
|
||||
const storedPlayer = playerStorage.fetchPlayer(player);
|
||||
if (messageType === "EnterGame") {
|
||||
try {
|
||||
entityStorage[player.UserId] = loadInPlayer(player);
|
||||
storedPlayer.loadIn();
|
||||
messageClient(player, "enterGame");
|
||||
} catch (thrownError) {
|
||||
if (typeIs(thrownError, "string")) {
|
||||
|
@ -30,11 +29,11 @@ function handleInput(player: Player, messageType: unknown, messageContent: unkno
|
|||
}
|
||||
} else if (messageType === "move") {
|
||||
if (typeIs(messageContent, "Vector3")) {
|
||||
moveEntity(entityStorage[player.UserId], messageContent);
|
||||
storedPlayer.setPosition(messageContent)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Action phase
|
||||
Players.PlayerAdded.Connect(addPlayer);
|
||||
Players.PlayerRemoving.Connect(removePlayer);
|
||||
bindToInput(handleInput);
|
||||
bindToClientMessage(handleClientMessage);
|
||||
|
|
41
src/services.d.ts
vendored
41
src/services.d.ts
vendored
|
@ -1,33 +1,8 @@
|
|||
type puppetEntry = ["Character", Player] | ["Placeholder", "Placeholder"];
|
||||
/*
|
||||
type bodyPart = "root" | "torso" | "head" | "leftArm" | "rightArm" | "leftLeg" | "rightLeg";
|
||||
type serverMessageType = "init" | "promptError" | "enterGame";
|
||||
type clientMessageType = "move" | "placeholder";
|
||||
|
||||
interface saveDataEntry {
|
||||
placeholder: string;
|
||||
}
|
||||
interface playerStorageEntry {
|
||||
inMainMenu: boolean;
|
||||
// + Other data that is unique to players but does not persist between sessions
|
||||
saveData: saveDataEntry;
|
||||
entity?: entity;
|
||||
}
|
||||
interface puppet {
|
||||
entry: puppetEntry;
|
||||
model: Model;
|
||||
rootPart: Part;
|
||||
//placeholder: (x: string) => string; // + "Puppet string" functions will (not?) go here
|
||||
}
|
||||
interface entity {
|
||||
baseStats: [number, number, number, number]; // MaxHealth, Attack, Speed, Defense (things used for calculation, only modified by buffs and debuffs)
|
||||
baseAmounts: [number, number]; // Health, Barrier (things of indescribable importance)
|
||||
puppet: puppet;
|
||||
}
|
||||
interface event {
|
||||
winEvents?: event[]; // A list of events that need to return true (in sequence) to complete this event
|
||||
winEntities?: entity[]; // A list of entities that need to die to complete the event
|
||||
timeout?: number; // A timeout for the event; passes a lose condition if there are other completion requirements that have not been satisfied
|
||||
}
|
||||
// + Why can the client see all of these?
|
||||
|
||||
type meshType = "Ball";
|
||||
type effectState = [CFrame, Vector3, Color3, number]; // The number is transparency
|
||||
|
@ -36,6 +11,18 @@ type effectEntry = [meshType, EnumItem, effectState[]]; // The enumitem is mater
|
|||
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)
|
||||
}
|
||||
*/
|
||||
// Genuinely require being on both sides - but in the services file? No shot!
|
||||
type acceptedControls = Enum.KeyCode[] // + Include controller "keys"
|
||||
interface controlBindings {
|
||||
clicker1: acceptedControls; // What is used to click on things (enemies in game, UI elements)
|
||||
diamond1: acceptedControls; // Diamond controls
|
||||
diamond2: acceptedControls;
|
||||
diamond3: acceptedControls;
|
||||
diamond4: acceptedControls;
|
||||
special1: acceptedControls; // Special controls
|
||||
}
|
||||
|
||||
|
||||
/*interface hookInEntry {
|
||||
name: string;
|
||||
|
|
|
@ -1,18 +1,27 @@
|
|||
// "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, movePuppet } from "./Puppetmaster";
|
||||
export function makeEntity(puppetEntry: puppetEntry) {
|
||||
const newEntity: entity = {
|
||||
baseStats: [0, 0, 0, 0],
|
||||
baseAmounts: [0, 0],
|
||||
puppet: makePuppet(puppetEntry),
|
||||
};
|
||||
return newEntity;
|
||||
import { makePuppet, puppet, puppetEntry } from "./Puppetmaster";
|
||||
type stats = [maxHealth: number, attack: number, speed: number, defense: number] // values used for calculation, only modified by buffs and debuffs
|
||||
type amounts = [health: number, barrier: number] // values used to store an entity's current status (more existential than stats)
|
||||
|
||||
export interface entity {
|
||||
setPosition: (location: Vector3) => void;
|
||||
}
|
||||
|
||||
// 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);
|
||||
class entityHandler implements entity {
|
||||
constructor(baseStats: stats, baseAmounts: amounts, puppetEntry: puppetEntry) {
|
||||
this.baseStats = baseStats;
|
||||
this.baseAmounts = baseAmounts;
|
||||
this.puppet = makePuppet(puppetEntry);
|
||||
};
|
||||
setPosition(location: Vector3) {
|
||||
this.puppet.movePuppet(location);
|
||||
}
|
||||
baseStats: stats;
|
||||
baseAmounts: amounts; // Health, Barrier (things of indescribable importance)
|
||||
puppet: puppet;
|
||||
}
|
||||
|
||||
export function makeEntity(puppetEntry: puppetEntry, baseStats = [100, 1, 16, 0] as stats, baseAmounts = [100, 0] as amounts) {
|
||||
return new entityHandler(baseStats, baseAmounts, puppetEntry);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
// "The": Handle events.
|
||||
// WORST CONDITION RigHT NOW
|
||||
import { makeEntity } from "./EntityManager";
|
||||
import { makeEntity, entity } from "./EntityManager";
|
||||
interface event {
|
||||
winEvents?: event[]; // A list of events that need to return true (in sequence) to complete this event
|
||||
winEntities?: entity[]; // A list of entities that need to die to complete the event
|
||||
timeout?: number; // A timeout for the event; passes a lose condition if there are other completion requirements that have not been satisfied
|
||||
}
|
||||
export function runEvent(event: event) {
|
||||
let complete = false;
|
||||
const startTime = os.clock();
|
||||
|
|
|
@ -1,28 +1,66 @@
|
|||
// "PlayerManager": Handle the data of players. This involves receiving them when they arrive, cleaning up after they exit, teleporting them, etc.
|
||||
import { makeEntity } from "./EntityManager";
|
||||
import { makeEntity, entity } from "./EntityManager";
|
||||
|
||||
export function initPlayer(player: Player) {
|
||||
const newEntry: playerStorageEntry = {
|
||||
inMainMenu: true,
|
||||
saveData: {
|
||||
placeholder: "placeholder",
|
||||
},
|
||||
interface saveDataEntry { // + May need to move this to archiver
|
||||
placeholder: string;
|
||||
}
|
||||
export interface storedPlayer {
|
||||
teleportToServer: () => void;
|
||||
setPosition: (location: Vector3) => void;
|
||||
loadIn: () => void;
|
||||
}
|
||||
|
||||
class storedPlayerHandler implements storedPlayer {
|
||||
constructor(player: Player) {
|
||||
this.player = player;
|
||||
this.inMainMenu = true;
|
||||
this.saveData = {placeholder: "fortnite"};
|
||||
}
|
||||
teleportToServer() {
|
||||
// + Do checking related to where the player is allowed to go
|
||||
// + Teleport player to other server, sending a message to have them load in automatically
|
||||
};
|
||||
// + Load player's datastore into server store
|
||||
return newEntry; // Return the entry to be put into the server store
|
||||
setPosition(location: Vector3) {
|
||||
if (this.entity) {
|
||||
this.entity.setPosition(location);
|
||||
}
|
||||
};
|
||||
loadIn() {
|
||||
this.entity = makeEntity(["Character", this.player]);
|
||||
// + Give the entity the stats it's supposed to have, load from save data maybe?
|
||||
};
|
||||
player: Player;
|
||||
inMainMenu: boolean;
|
||||
// + Other data that is unique to players but does not persist between sessions
|
||||
saveData: saveDataEntry;
|
||||
entity?: entity;
|
||||
}
|
||||
export function deinitPlayer(entry: playerStorageEntry | undefined, player: Player) {
|
||||
assert(entry, "Trying to remove entry of player " + player.DisplayName + ", but entry does not exist!");
|
||||
// ? Tell the entity to unload, if it still exists (the entity will tell the other clients to remove the player)
|
||||
// + Unload player's server store to datastores
|
||||
return undefined; // A nil entry to replace the entry to be wiped and maybe a success value in a wrapper
|
||||
|
||||
export interface playerStorage {
|
||||
initPlayer: (player: Player) => void;
|
||||
deinitPlayer: (player: Player) => void;
|
||||
fetchPlayer: (player: Player) => storedPlayer;
|
||||
}
|
||||
export function loadInPlayer(player: Player) {
|
||||
const entity = makeEntity(["Character", player]);
|
||||
// + Give the entity the stats it's supposed to have, load from save data maybe?
|
||||
return entity;
|
||||
}
|
||||
export function teleportPlayer() {
|
||||
// + Do checking related to where the player is allowed to go
|
||||
// + Teleport player to other server, sending a message to have them load in automatically
|
||||
|
||||
class playerStorageHandler implements playerStorage {
|
||||
constructor() {};
|
||||
initPlayer(player: Player) {
|
||||
this.playerStorageArray[player.UserId] = new storedPlayerHandler(player);
|
||||
// + Load player's datastore into server store
|
||||
};
|
||||
deinitPlayer(player: Player) {
|
||||
const entry = this.playerStorageArray[player.UserId];
|
||||
assert(entry, "Trying to remove entry of player " + player.DisplayName + ", but entry does not exist!");
|
||||
// ? Tell the entity to unload, if it still exists (the entity will tell the other clients to remove the player)
|
||||
// + Unload player's server store to datastores
|
||||
return undefined; // A nil entry to replace the entry to be wiped and maybe a success value in a wrapper
|
||||
};
|
||||
fetchPlayer(player: Player) {
|
||||
return this.playerStorageArray[player.UserId];
|
||||
}
|
||||
playerStorageArray: storedPlayerHandler[] = [];
|
||||
}
|
||||
|
||||
export function makePlayerStorage() {
|
||||
return new playerStorageHandler();
|
||||
}
|
|
@ -5,34 +5,53 @@ const puppetLibraries = {
|
|||
["Placeholder"]: m1,
|
||||
};
|
||||
|
||||
export function makePuppet(puppetEntry: puppetEntry) {
|
||||
export type puppetEntry = ["Character", Player] | ["Placeholder", "Placeholder"];
|
||||
|
||||
export interface puppet {
|
||||
movePuppet: (location: Vector3) => void; // + Success value maybe?
|
||||
}
|
||||
/* interface puppetHandler extends puppet {
|
||||
entry: puppetEntry;
|
||||
} */
|
||||
/* interface completePuppetHandler extends puppetHandler {
|
||||
model: Model;
|
||||
rootPart: Part;
|
||||
} */
|
||||
|
||||
function makePuppetModel(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],
|
||||
};
|
||||
return puppetLibraries[puppetEntry[0]].makeModel(puppetEntry[1]) as [Model, Part];
|
||||
} else {
|
||||
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);
|
||||
function verifyPuppetExistence(puppetHandler: puppetHandler)/*: puppetHandler is completePuppetHandler */{ // + Making this do type checking is currently beyond me
|
||||
if (!puppetHandler.rootPart || !puppetHandler.rootPart.Parent) {
|
||||
print("Regenerating puppet!");
|
||||
[puppetHandler.model, puppetHandler.rootPart] = makePuppetModel(puppetHandler.entry);
|
||||
}
|
||||
// return true;
|
||||
}
|
||||
class puppetHandler implements puppet {
|
||||
constructor(puppetEntry: puppetEntry) {
|
||||
this.entry = puppetEntry;
|
||||
};
|
||||
|
||||
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;
|
||||
movePuppet(location: Vector3) {
|
||||
print("executing puppet move");
|
||||
verifyPuppetExistence(this);
|
||||
if (!this.rootPart) { // + Remove this once you get better at typescript
|
||||
throw "Fornite";
|
||||
}
|
||||
this.rootPart.CFrame = new CFrame(location);
|
||||
}
|
||||
|
||||
entry: puppetEntry;
|
||||
model?: Model;
|
||||
rootPart?: Part;
|
||||
};
|
||||
|
||||
export function makePuppet(puppetEntry: puppetEntry) {
|
||||
return new puppetHandler(puppetEntry);// return newPuppet as puppet;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue