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";
|
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');
|
assert(Output?.IsA("RemoteEvent"), 'Remote event "Input" is of incorrect class or nil');
|
||||||
Output.OnClientEvent.Connect(functionToBind);
|
Output.OnClientEvent.Connect(functionToBind);
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ interface effectHandler extends effectMaker, effectRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeEffectHandler(effectFolder: Folder) {
|
export function makeEffectHandler(effectFolder: Folder) {
|
||||||
const effectHandler: effectHandler = {
|
return {
|
||||||
meshPartEffect: function(meshPart: MeshPart, material: Enum.Material, effectKeypoints: effectKeypoint[], priority?: number) {
|
meshPartEffect: function(meshPart: MeshPart, material: Enum.Material, effectKeypoints: effectKeypoint[], priority?: number) {
|
||||||
const effectMeshPart = meshPart.Clone();
|
const effectMeshPart = meshPart.Clone();
|
||||||
effectMeshPart.Material = material;
|
effectMeshPart.Material = material;
|
||||||
|
@ -102,8 +102,7 @@ export function makeEffectHandler(effectFolder: Folder) {
|
||||||
|
|
||||||
EFFECT_FOLDER: effectFolder,
|
EFFECT_FOLDER: effectFolder,
|
||||||
effectsToRun: [],
|
effectsToRun: [],
|
||||||
}
|
} as effectHandler;
|
||||||
return effectHandler;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
local function horseEffModule(o,typ,a1,a2,a3,a4,a5,a6,a7)
|
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 Players = game.GetService("Players");
|
||||||
const UserInputService = game.GetService("UserInputService");
|
|
||||||
const RunService = game.GetService("RunService");
|
const RunService = game.GetService("RunService");
|
||||||
const Workspace = game.GetService("Workspace");
|
import { bindToServerMessage, messageServer } from "./ClientMessenger";
|
||||||
import { bindToOutput, messageServer } from "./ClientMessenger";
|
|
||||||
import { handleGuiInput, drawGui, closeGui } from "./GuiHandler";
|
import { handleGuiInput, drawGui, closeGui } from "./GuiHandler";
|
||||||
import { makeEffectHandler, effectRunner } from "./EffectMaker";
|
import { makeEffectHandler, effectRunner } from "./EffectMaker";
|
||||||
const LOCALPLAYER = Players.LocalPlayer;
|
const LOCALPLAYER = Players.LocalPlayer;
|
||||||
|
@ -12,8 +10,6 @@ assert(
|
||||||
PLAYERGUI && classIs(PLAYERGUI, "PlayerGui"),
|
PLAYERGUI && classIs(PLAYERGUI, "PlayerGui"),
|
||||||
'PlayerGui of "' + LOCALPLAYER.DisplayName + '"does not exist! (HOW???)',
|
'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;
|
let inMainMenu = true;
|
||||||
|
|
||||||
function openMainMenu(playerGui: PlayerGui) {
|
function openMainMenu(playerGui: PlayerGui) {
|
||||||
|
@ -26,29 +22,7 @@ function openMainMenu(playerGui: PlayerGui) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const hitParams = new RaycastParams();
|
function handleServerMessage(messageType: unknown, messageContent: unknown) {
|
||||||
//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") {
|
if (messageType === "init") {
|
||||||
openMainMenu(PLAYERGUI);
|
openMainMenu(PLAYERGUI);
|
||||||
inMainMenu = true;
|
inMainMenu = true;
|
||||||
|
@ -57,12 +31,12 @@ function handleOutput(messageType: unknown, messageContent: unknown) {
|
||||||
inMainMenu = false;
|
inMainMenu = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Action phase
|
// Bind functions
|
||||||
UserInputService.InputBegan.Connect(handleInput);
|
|
||||||
bindToOutput(handleOutput);
|
bindToServerMessage(handleServerMessage);
|
||||||
|
|
||||||
const effectRunners: effectRunner[] = [];
|
const effectRunners: effectRunner[] = [];
|
||||||
// Put stuff in the effectRunners table
|
// + Put stuff in the effectRunners table
|
||||||
RunService.RenderStepped.Connect(function(deltaTime) {
|
RunService.RenderStepped.Connect(function(deltaTime) {
|
||||||
effectRunners.forEach(effectRunner => {
|
effectRunners.forEach(effectRunner => {
|
||||||
effectRunner.runEffects(deltaTime)
|
effectRunner.runEffects(deltaTime)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { Input, Output } from "shared/Remotes";
|
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');
|
assert(Input?.IsA("RemoteEvent"), 'Remote event "Input" is of incorrect class or nil');
|
||||||
Input.OnServerEvent.Connect(functionToBind);
|
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');
|
assert(Output?.IsA("RemoteEvent"), 'Remote event "Output" is of incorrect class or nil');
|
||||||
Output.FireClient(client, messageType, messageContent);
|
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');
|
assert(Output?.IsA("RemoteEvent"), 'Remote event "Output" is of incorrect class or nil');
|
||||||
Output.FireAllClients(messageType, messageContent);
|
Output.FireAllClients(messageType, messageContent);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,23 @@
|
||||||
// "main": This is the core of reality. It serves as the highest-level abstraction.
|
// "main": This is the core of reality. It serves as the highest-level abstraction.
|
||||||
// + Prevent this from coupling with the entity manager, if possible
|
// + Prevent this from coupling with the entity manager, if possible
|
||||||
const Players = game.GetService("Players");
|
const Players = game.GetService("Players");
|
||||||
import { makeEntity, moveEntity } from "shared/EntityManager";
|
import { makePlayerStorage, playerStorage, storedPlayer } from "shared/PlayerManager";
|
||||||
import { initPlayer, deinitPlayer, loadInPlayer, teleportPlayer } from "shared/PlayerManager";
|
import { bindToClientMessage, messageClient, messageAllClients } from "./ServerMessenger";
|
||||||
import { bindToInput, messageClient, messageAllClients } from "./ServerMessenger";
|
const playerStorage: playerStorage = makePlayerStorage();
|
||||||
const playerStorage: (playerStorageEntry | undefined)[] = [];
|
|
||||||
const entityStorage: entity[] = [];
|
|
||||||
|
|
||||||
function addPlayer(player: Player) {
|
function addPlayer(player: Player) {
|
||||||
playerStorage[player.UserId] = initPlayer(player);
|
playerStorage.initPlayer(player);
|
||||||
messageClient(player, "init", "idk");
|
messageClient(player, "init", "idk");
|
||||||
}
|
}
|
||||||
function removePlayer(player: Player) {
|
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
|
// 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") {
|
if (messageType === "EnterGame") {
|
||||||
try {
|
try {
|
||||||
entityStorage[player.UserId] = loadInPlayer(player);
|
storedPlayer.loadIn();
|
||||||
messageClient(player, "enterGame");
|
messageClient(player, "enterGame");
|
||||||
} catch (thrownError) {
|
} catch (thrownError) {
|
||||||
if (typeIs(thrownError, "string")) {
|
if (typeIs(thrownError, "string")) {
|
||||||
|
@ -30,11 +29,11 @@ function handleInput(player: Player, messageType: unknown, messageContent: unkno
|
||||||
}
|
}
|
||||||
} else if (messageType === "move") {
|
} else if (messageType === "move") {
|
||||||
if (typeIs(messageContent, "Vector3")) {
|
if (typeIs(messageContent, "Vector3")) {
|
||||||
moveEntity(entityStorage[player.UserId], messageContent);
|
storedPlayer.setPosition(messageContent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Action phase
|
// Action phase
|
||||||
Players.PlayerAdded.Connect(addPlayer);
|
Players.PlayerAdded.Connect(addPlayer);
|
||||||
Players.PlayerRemoving.Connect(removePlayer);
|
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 bodyPart = "root" | "torso" | "head" | "leftArm" | "rightArm" | "leftLeg" | "rightLeg";
|
||||||
type serverMessageType = "init" | "promptError" | "enterGame";
|
type serverMessageType = "init" | "promptError" | "enterGame";
|
||||||
type clientMessageType = "move" | "placeholder";
|
type clientMessageType = "move" | "placeholder";
|
||||||
|
// + Why can the client see all of these?
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
type meshType = "Ball";
|
type meshType = "Ball";
|
||||||
type effectState = [CFrame, Vector3, Color3, number]; // The number is transparency
|
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 {
|
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)
|
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 {
|
/*interface hookInEntry {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -1,18 +1,27 @@
|
||||||
// "EntityManager": Create entities objects and deck them out with functions to use.
|
// "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.
|
// + Functions are here, as to avoid storing unecessary data in the server store.
|
||||||
import { makePuppet, movePuppet } from "./Puppetmaster";
|
import { makePuppet, puppet, puppetEntry } from "./Puppetmaster";
|
||||||
export function makeEntity(puppetEntry: puppetEntry) {
|
type stats = [maxHealth: number, attack: number, speed: number, defense: number] // values used for calculation, only modified by buffs and debuffs
|
||||||
const newEntity: entity = {
|
type amounts = [health: number, barrier: number] // values used to store an entity's current status (more existential than stats)
|
||||||
baseStats: [0, 0, 0, 0],
|
|
||||||
baseAmounts: [0, 0],
|
export interface entity {
|
||||||
puppet: makePuppet(puppetEntry),
|
setPosition: (location: Vector3) => void;
|
||||||
};
|
|
||||||
return newEntity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This exists because the main server should never see the puppets, but it is a bit weird
|
class entityHandler implements entity {
|
||||||
export function moveEntity(entity: entity | undefined, location: Vector3) {
|
constructor(baseStats: stats, baseAmounts: amounts, puppetEntry: puppetEntry) {
|
||||||
if (entity) {
|
this.baseStats = baseStats;
|
||||||
entity.puppet = movePuppet(entity.puppet, location);
|
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.
|
// "The": Handle events.
|
||||||
// WORST CONDITION RigHT NOW
|
// 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) {
|
export function runEvent(event: event) {
|
||||||
let complete = false;
|
let complete = false;
|
||||||
const startTime = os.clock();
|
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.
|
// "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) {
|
interface saveDataEntry { // + May need to move this to archiver
|
||||||
const newEntry: playerStorageEntry = {
|
placeholder: string;
|
||||||
inMainMenu: true,
|
|
||||||
saveData: {
|
|
||||||
placeholder: "placeholder",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
// + Load player's datastore into server store
|
|
||||||
return newEntry; // Return the entry to be put into the server store
|
|
||||||
}
|
}
|
||||||
export function deinitPlayer(entry: playerStorageEntry | undefined, player: Player) {
|
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
|
||||||
|
};
|
||||||
|
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 interface playerStorage {
|
||||||
|
initPlayer: (player: Player) => void;
|
||||||
|
deinitPlayer: (player: Player) => void;
|
||||||
|
fetchPlayer: (player: Player) => storedPlayer;
|
||||||
|
}
|
||||||
|
|
||||||
|
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!");
|
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)
|
// ? 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
|
// + 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
|
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 loadInPlayer(player: Player) {
|
|
||||||
const entity = makeEntity(["Character", player]);
|
export function makePlayerStorage() {
|
||||||
// + Give the entity the stats it's supposed to have, load from save data maybe?
|
return new playerStorageHandler();
|
||||||
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
|
|
||||||
}
|
}
|
|
@ -5,34 +5,53 @@ const puppetLibraries = {
|
||||||
["Placeholder"]: m1,
|
["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") {
|
if (puppetEntry[0] === "Character") {
|
||||||
const model: [Model, Part] = puppetLibraries[puppetEntry[0]].makeModel(puppetEntry[1]);
|
return puppetLibraries[puppetEntry[0]].makeModel(puppetEntry[1]) as [Model, Part];
|
||||||
return {
|
|
||||||
entry: puppetEntry,
|
|
||||||
model: model[0],
|
|
||||||
rootPart: model[1],
|
|
||||||
};
|
|
||||||
} else {
|
} else {
|
||||||
throw 'Invalid puppet type "' + puppetEntry[0] + '"!';
|
throw 'Invalid puppet type "' + puppetEntry[0] + '"!';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function verifyPuppetExistence(puppet: puppet) {
|
function verifyPuppetExistence(puppetHandler: puppetHandler)/*: puppetHandler is completePuppetHandler */{ // + Making this do type checking is currently beyond me
|
||||||
if (puppet.rootPart.Parent) {
|
if (!puppetHandler.rootPart || !puppetHandler.rootPart.Parent) {
|
||||||
// Placeholder; puppet integrity will include other body parts
|
print("Regenerating puppet!");
|
||||||
return puppet;
|
[puppetHandler.model, puppetHandler.rootPart] = makePuppetModel(puppetHandler.entry);
|
||||||
} else {
|
|
||||||
print("No puppet!");
|
|
||||||
return makePuppet(puppet.entry);
|
|
||||||
}
|
}
|
||||||
|
// return true;
|
||||||
}
|
}
|
||||||
|
class puppetHandler implements puppet {
|
||||||
|
constructor(puppetEntry: puppetEntry) {
|
||||||
|
this.entry = puppetEntry;
|
||||||
|
};
|
||||||
|
|
||||||
export function movePuppet(puppet: puppet, location: Vector3) {
|
movePuppet(location: Vector3) {
|
||||||
print("executing puppet move");
|
print("executing puppet move");
|
||||||
puppet = verifyPuppetExistence(puppet); //const newPuppet = verifyPuppetExistence(puppet);
|
verifyPuppetExistence(this);
|
||||||
//puppet.rootPart = newPuppet.rootPart;
|
if (!this.rootPart) { // + Remove this once you get better at typescript
|
||||||
//puppet.model = newPuppet.model;
|
throw "Fornite";
|
||||||
puppet.rootPart.CFrame = new CFrame(location);
|
}
|
||||||
return puppet;
|
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