public Layer(ClientResourceLocator?resourceLocator = null, string?layerPathLua = null, params object[] args) { ResourceLocator = resourceLocator ?? ClientResourceLocator.Default; m_spriteRenderer = new BasicSpriteRenderer(ResourceLocator); m_resources = new ClientResourceManager(ResourceLocator); m_script = new ScriptProgram(ResourceLocator); m_renderer2D = new RenderBatch2D(m_resources); m_drivingScriptFileName = layerPathLua; m_drivingScriptArgs = args; m_script["KeyCode"] = typeof(KeyCode); m_script["MouseButton"] = typeof(MouseButton); m_script["ControllerAxisStyle"] = typeof(ControllerAxisStyle); m_script["theori"] = tblTheori = m_script.NewTable(); tblTheori["isFirstLaunch"] = (Func <bool>)(() => Host.IsFirstLaunch); tblTheori["audio"] = tblTheoriAudio = m_script.NewTable(); tblTheori["charts"] = tblTheoriCharts = m_script.NewTable(); tblTheori["config"] = tblTheoriConfig = m_script.NewTable(); tblTheori["game"] = tblTheoriGame = m_script.NewTable(); tblTheori["graphics"] = tblTheoriGraphics = m_script.NewTable(); tblTheori["input"] = tblTheoriInput = m_script.NewTable(); tblTheori["layer"] = tblTheoriLayer = m_script.NewTable(); tblTheori["modes"] = tblTheoriModes = m_script.NewTable(); tblTheori["net"] = tblTheoriNet = m_script.NewTable(); tblTheoriInput["textInput"] = evtTextInput = m_script.NewEvent(); tblTheoriInput["keyboard"] = tblTheoriInputKeyboard = m_script.NewTable(); tblTheoriInput["mouse"] = tblTheoriInputMouse = m_script.NewTable(); tblTheoriInput["gamepad"] = tblTheoriInputGamepad = m_script.NewTable(); tblTheoriInput["controller"] = tblTheoriInputController = m_script.NewTable(); tblTheoriInputKeyboard["isDown"] = (Func <KeyCode, bool>)(key => UserInputService.IsKeyDown(key)); tblTheoriInputKeyboard["pressed"] = evtKeyPressed = m_script.NewEvent(); tblTheoriInputKeyboard["released"] = evtKeyReleased = m_script.NewEvent(); tblTheoriInputKeyboard["pressedRaw"] = evtRawKeyPressed = m_script.NewEvent(); tblTheoriInputKeyboard["releasedRaw"] = evtRawKeyReleased = m_script.NewEvent(); tblTheoriInputMouse["pressed"] = evtMousePressed = m_script.NewEvent(); tblTheoriInputMouse["released"] = evtMouseReleased = m_script.NewEvent(); tblTheoriInputMouse["moved"] = evtMouseMoved = m_script.NewEvent(); tblTheoriInputMouse["scrolled"] = evtMouseScrolled = m_script.NewEvent(); tblTheoriInputMouse["pressedRaw"] = evtRawMousePressed = m_script.NewEvent(); tblTheoriInputMouse["releasedRaw"] = evtRawMouseReleased = m_script.NewEvent(); tblTheoriInputMouse["movedRaw"] = evtRawMouseMoved = m_script.NewEvent(); tblTheoriInputMouse["scrolledRaw"] = evtRawMouseScrolled = m_script.NewEvent(); tblTheoriInputMouse["getMousePosition"] = (Func <DynValue>)(() => NewTuple(NewNumber(UserInputService.MouseX), NewNumber(UserInputService.MouseY))); tblTheoriInputGamepad["connected"] = evtGamepadConnected = m_script.NewEvent(); tblTheoriInputGamepad["disconnected"] = evtGamepadDisconnected = m_script.NewEvent(); tblTheoriInputGamepad["pressed"] = evtGamepadPressed = m_script.NewEvent(); tblTheoriInputGamepad["released"] = evtGamepadReleased = m_script.NewEvent(); tblTheoriInputGamepad["axisChanged"] = evtGamepadAxisChanged = m_script.NewEvent(); tblTheoriInputGamepad["pressedRaw"] = evtRawGamepadPressed = m_script.NewEvent(); tblTheoriInputGamepad["releasedRaw"] = evtRawGamepadReleased = m_script.NewEvent(); tblTheoriInputGamepad["axisChangedRaw"] = evtRawGamepadAxisChanged = m_script.NewEvent(); tblTheoriInputController["added"] = evtControllerAdded = m_script.NewEvent(); tblTheoriInputController["removed"] = evtControllerRemoved = m_script.NewEvent(); tblTheoriInputController["pressed"] = evtControllerPressed = m_script.NewEvent(); tblTheoriInputController["released"] = evtControllerReleased = m_script.NewEvent(); tblTheoriInputController["axisChanged"] = evtControllerAxisChanged = m_script.NewEvent(); tblTheoriInputController["axisTicked"] = evtControllerAxisTicked = m_script.NewEvent(); tblTheori["doStaticLoadsAsync"] = (Func <bool>)(() => StaticResources.LoadAll()); tblTheori["finalizeStaticLoads"] = (Func <bool>)(() => StaticResources.FinalizeLoad()); tblTheoriAudio["queueStaticAudioLoad"] = (Func <string, AudioHandle>)(audioName => StaticResources.QueueAudioLoad($"audio/{ audioName }")); tblTheoriAudio["getStaticAudio"] = (Func <string, AudioHandle>)(audioName => StaticResources.GetAudio($"audio/{ audioName }")); tblTheoriAudio["queueAudioLoad"] = (Func <string, AudioHandle>)(audioName => m_resources.QueueAudioLoad($"audio/{ audioName }")); tblTheoriAudio["getAudio"] = (Func <string, AudioHandle>)(audioName => m_resources.GetAudio($"audio/{ audioName }")); tblTheoriAudio["createFakeAudio"] = (Func <int, int, AudioHandle>)((sampleRate, channels) => new FakeAudioSource(sampleRate, channels)); tblTheoriCharts["setDatabaseToIdle"] = (Action)(() => Client.DatabaseWorker.SetToIdle()); tblTheoriCharts["getDatabaseState"] = (Func <string>)(() => Client.DatabaseWorker.State.ToString()); tblTheoriCharts["setDatabaseToClean"] = (Action <DynValue>)(arg => { Client.DatabaseWorker.SetToClean(arg == DynValue.Void ? (Action?)null : () => m_script.Call(arg)); }); tblTheoriCharts["setDatabaseToPopulate"] = NewCallback((ctx, args) => { Action?callback = args.Count == 0 ? (Action?)null : () => ctx.Call(args[0]); Client.DatabaseWorker.SetToPopulate(callback); return(Nil); }); tblTheoriCharts["create"] = (Func <string, ChartHandle>)(modeName => { var mode = GameMode.GetInstance(modeName); //if (mode == null) return DynValue.Nil; return(new ChartHandle(m_resources, m_script, Client.DatabaseWorker, mode !.GetChartFactory().CreateNew())); }); tblTheoriCharts["newEntity"] = (Func <string, Entity>)(entityTypeId => { var entityType = Entity.GetEntityTypeById(entityTypeId); return((Entity)Activator.CreateInstance(entityType !)); }); tblTheoriCharts["saveChartToDatabase"] = (Action <Chart>)(chart => { var ser = chart.GameMode.CreateChartSerializer(TheoriConfig.ChartsDirectory, chart.Info.ChartFileType) ?? new TheoriChartSerializer(TheoriConfig.ChartsDirectory, chart.GameMode); var setSer = new ChartSetSerializer(TheoriConfig.ChartsDirectory); setSer.SaveToFile(chart.SetInfo); ser.SaveToFile(chart); }); tblTheoriCharts["createCollection"] = (Action <string>)(collectionName => Client.DatabaseWorker.CreateCollection(collectionName)); tblTheoriCharts["addChartToCollection"] = (Action <string, ChartInfoHandle>)((collectionName, chart) => Client.DatabaseWorker.AddChartToCollection(collectionName, chart)); tblTheoriCharts["removeChartFromCollection"] = (Action <string, ChartInfoHandle>)((collectionName, chart) => Client.DatabaseWorker.RemoveChartFromCollection(collectionName, chart)); tblTheoriCharts["getCollectionNames"] = (Func <string[]>)(() => Client.DatabaseWorker.CollectionNames); tblTheoriCharts["getFolderNames"] = (Func <string[]>)(() => Directory.GetDirectories(TheoriConfig.ChartsDirectory).Select(d => Path.GetFileName(d)).ToArray()); tblTheoriCharts["getChartSets"] = (Func <List <ChartSetInfoHandle> >)(() => Client.DatabaseWorker.ChartSets.Select(info => new ChartSetInfoHandle(m_resources, m_script, Client.DatabaseWorker, info)).ToList()); tblTheoriCharts["getScores"] = (Func <ChartInfoHandle, ScoreData[]>)(chart => ChartDatabaseService.GetScoresForChart(chart.Object)); tblTheoriCharts["getChartSetsFiltered"] = (Func <string?, DynValue, DynValue, DynValue, List <List <ChartInfoHandle> > >)((col, a, b, c) => { Logger.Log("Attempting to filter charts..."); var setInfoHandles = new Dictionary <ChartSetInfo, ChartSetInfoHandle>(); ChartSetInfoHandle GetSetInfoHandle(ChartSetInfo chartSet) { if (!setInfoHandles.TryGetValue(chartSet, out var result)) { result = setInfoHandles[chartSet] = new ChartSetInfoHandle(m_resources, m_script, Client.DatabaseWorker, chartSet); } return(result); } Logger.Log(col ?? "null"); var charts = col != null ? Client.DatabaseWorker.GetChartsInCollection(col) : Client.DatabaseWorker.Charts; var filteredCharts = from initialChart in charts let handle = new ChartInfoHandle(GetSetInfoHandle(initialChart.Set), initialChart) where m_script.Call(a, handle).CastToBool() select handle; var groupedCharts = filteredCharts.OrderBy(chart => m_script.Call(b, chart), DynValueComparer.Instance) .GroupBy(chart => m_script.Call(b, chart)) .Select(theGroup => (theGroup.Key, Value: theGroup .OrderBy(chart => chart.DifficultyIndex) .ThenBy(chart => chart.DifficultyName) .ThenBy(chart => m_script.Call(c, chart), DynValueComparer.Instance) .Select(chart => chart) .ToList())) .OrderBy(l => l.Key, DynValueComparer.Instance) .Select(l => l.Value) .ToList(); return(groupedCharts); }); tblTheoriConfig["get"] = (Func <string, DynValue>)(key => FromObject(m_script.Script, UserConfigManager.GetFromKey(key))); tblTheoriConfig["set"] = (Action <string, DynValue>)((key, value) => UserConfigManager.SetFromKey(key, value.ToObject())); tblTheoriConfig["save"] = (Action)(() => UserConfigManager.SaveToFile()); tblTheoriGame["exit"] = (Action)(() => Host.Exit()); tblTheoriGraphics["queueStaticTextureLoad"] = (Func <string, Texture>)(textureName => StaticResources.QueueTextureLoad($"textures/{ textureName }")); tblTheoriGraphics["getStaticTexture"] = (Func <string, Texture>)(textureName => StaticResources.GetTexture($"textures/{ textureName }")); tblTheoriGraphics["queueTextureLoad"] = (Func <string, Texture>)(textureName => m_resources.QueueTextureLoad($"textures/{ textureName }")); tblTheoriGraphics["getTexture"] = (Func <string, Texture>)(textureName => m_resources.GetTexture($"textures/{ textureName }")); tblTheoriGraphics["createStaticFont"] = (Func <string, VectorFont?>)(fontName => ResourceLocator.OpenFileStreamWithExtension($"fonts/{ fontName }", new[] { ".ttf", ".otf" }, out string _) is Stream fs ? staticFonts[fontName] = new VectorFont(fs) : null); tblTheoriGraphics["createFont"] = (Func <string, VectorFont?>)(fontName => ResourceLocator.OpenFileStreamWithExtension($"fonts/{ fontName }", new[] { ".ttf", ".otf" }, out string _) is Stream fs ? new VectorFont(fs) : null); tblTheoriGraphics["getStaticFont"] = (Func <string, VectorFont?>)(fontName => staticFonts.TryGetValue(fontName, out var font) ? font : null); //tblTheoriGraphics["getFont"] = (Func<string, VectorFont>)(fontName => m_resources.GetTexture($"fonts/{ fontName }")); tblTheoriGraphics["getViewportSize"] = (Func <DynValue>)(() => NewTuple(NewNumber(Window.Width), NewNumber(Window.Height))); tblTheoriGraphics["createPathCommands"] = (Func <Path2DCommands>)(() => new Path2DCommands()); tblTheoriGraphics["flush"] = (Action)(() => m_batch?.Flush()); tblTheoriGraphics["saveTransform"] = (Action)(() => m_batch?.SaveTransform()); tblTheoriGraphics["restoreTransform"] = (Action)(() => m_batch?.RestoreTransform()); tblTheoriGraphics["resetTransform"] = (Action)(() => m_batch?.ResetTransform()); tblTheoriGraphics["translate"] = (Action <float, float>)((x, y) => m_batch?.Translate(x, y)); tblTheoriGraphics["rotate"] = (Action <float>)(d => m_batch?.Rotate(d)); tblTheoriGraphics["scale"] = (Action <float, float>)((x, y) => m_batch?.Scale(x, y)); tblTheoriGraphics["shear"] = (Action <float, float>)((x, y) => m_batch?.Shear(x, y)); tblTheoriGraphics["setFillToColor"] = (Action <float, float, float, float>)((r, g, b, a) => m_batch?.SetFillColor(r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f)); tblTheoriGraphics["setFillToTexture"] = (Action <Texture, float, float, float, float>)((texture, r, g, b, a) => m_batch?.SetFillTexture(texture, new Vector4(r, g, b, a) / 255.0f)); tblTheoriGraphics["fillRect"] = (Action <float, float, float, float>)((x, y, w, h) => m_batch?.FillRectangle(x, y, w, h)); tblTheoriGraphics["fillRoundedRect"] = (Action <float, float, float, float, float>)((x, y, w, h, r) => m_batch?.FillRoundedRectangle(x, y, w, h, r)); tblTheoriGraphics["fillRoundedRectVarying"] = (Action <float, float, float, float, float, float, float, float>)((x, y, w, h, rtl, rtr, rbr, rbl) => m_batch?.FillRoundedRectangleVarying(x, y, w, h, rtl, rtr, rbr, rbl)); tblTheoriGraphics["setFont"] = (Action <VectorFont?>)(font => m_batch?.SetFont(font)); tblTheoriGraphics["setFontSize"] = (Action <int>)(size => m_batch?.SetFontSize(size)); tblTheoriGraphics["setTextAlign"] = (Action <Anchor>)(align => m_batch?.SetTextAlign(align)); tblTheoriGraphics["fillString"] = (Action <string, float, float>)((text, x, y) => m_batch?.FillString(text, x, y)); tblTheoriGraphics["measureString"] = (Func <string, DynValue>)(text => { var bounds = m_batch?.MeasureString(text) !.Value; return(NewTuple(NewNumber(bounds.X), NewNumber(bounds.Y))); }); tblTheoriGraphics["fillPathAt"] = (Action <Path2DCommands, float, float, float, float>)((path, x, y, sx, sy) => m_batch?.FillPathAt(path, x, y, sx, sy)); tblTheoriGraphics["saveScissor"] = (Action)(() => m_batch?.SaveScissor()); tblTheoriGraphics["restoreScissor"] = (Action)(() => m_batch?.RestoreScissor()); tblTheoriGraphics["resetScissor"] = (Action)(() => m_batch?.ResetScissor()); tblTheoriGraphics["scissor"] = (Action <float, float, float, float>)((x, y, w, h) => m_batch?.Scissor(x, y, w, h)); tblTheoriGraphics["openCurtain"] = (Action)OpenCurtain; tblTheoriGraphics["closeCurtain"] = (Action <float, DynValue?>)((duration, callback) => { Action?onClosed = (callback == null || callback == Nil) ? (Action?)null : () => m_script.Call(callback !); if (duration <= 0) { CloseCurtain(onClosed); } else { CloseCurtain(duration, onClosed); } });