diff --git a/app/Transformers/Api/Client/ServerTransformer.php b/app/Transformers/Api/Client/ServerTransformer.php index 92b9ea0bf..a787246bf 100644 --- a/app/Transformers/Api/Client/ServerTransformer.php +++ b/app/Transformers/Api/Client/ServerTransformer.php @@ -62,6 +62,7 @@ class ServerTransformer extends BaseClientTransformer 'cpu' => $server->cpu, ], 'invocation' => $service->handle($server, ! $this->getUser()->can(Permission::ACTION_STARTUP_READ, $server)), + 'egg_features' => $server->egg->inherit_features, 'feature_limits' => [ 'databases' => $server->database_limit, 'allocations' => $server->allocation_limit, diff --git a/config/egg_features/eula.php b/config/egg_features/eula.php new file mode 100644 index 000000000..e5fb8727b --- /dev/null +++ b/config/egg_features/eula.php @@ -0,0 +1,16 @@ + 0) ? data.description : null) : null, limits: { ...data.limits }, + eggFeatures: data.egg_features || [], featureLimits: { ...data.feature_limits }, isSuspended: data.is_suspended, isInstalling: data.is_installing, diff --git a/resources/scripts/components/server/ServerConsole.tsx b/resources/scripts/components/server/ServerConsole.tsx index ed24d4aa9..4735488fc 100644 --- a/resources/scripts/components/server/ServerConsole.tsx +++ b/resources/scripts/components/server/ServerConsole.tsx @@ -8,6 +8,7 @@ import ServerContentBlock from '@/components/elements/ServerContentBlock'; import ServerDetailsBlock from '@/components/server/ServerDetailsBlock'; import isEqual from 'react-fast-compare'; import PowerControls from '@/components/server/PowerControls'; +import { EulaModalFeature } from '@feature/index'; export type PowerAction = 'start' | 'stop' | 'restart' | 'kill'; @@ -16,6 +17,8 @@ const ChunkedStatGraphs = lazy(() => import(/* webpackChunkName: "graphs" */'@/c const ServerConsole = () => { const isInstalling = ServerContext.useStoreState(state => state.server.data!.isInstalling); + // @ts-ignore + const eggFeatures: string[] = ServerContext.useStoreState(state => state.server.data!.eggFeatures, isEqual); return ( @@ -41,6 +44,11 @@ const ServerConsole = () => { + {eggFeatures.includes('eula') && + + + + } ); diff --git a/resources/scripts/components/server/features/eula/EulaModalFeature.tsx b/resources/scripts/components/server/features/eula/EulaModalFeature.tsx new file mode 100644 index 000000000..79e907d7f --- /dev/null +++ b/resources/scripts/components/server/features/eula/EulaModalFeature.tsx @@ -0,0 +1,41 @@ +import React, { useEffect, useState } from 'react'; +import { ServerContext } from '@/state/server'; +import Modal from '@/components/elements/Modal'; +import tw from 'twin.macro'; + +const EulaModalFeature = () => { + const [ visible, setVisible ] = useState(false); + const status = ServerContext.useStoreState(state => state.status.value); + const { connected, instance } = ServerContext.useStoreState(state => state.socket); + + useEffect(() => { + if (!connected || !instance || status === 'running') return; + + const listener = (line: string) => { + if (line.toLowerCase().indexOf('you need to agree to the eula in order to run the server') >= 0) { + setVisible(true); + } + }; + + instance.addListener('console output', listener); + + return () => { + instance.removeListener('console output', listener); + }; + }, [ connected, instance, status ]); + + return ( + !visible ? + null + : + setVisible(false)}> +

EULA Not Accepted

+

+ It looks like you have not yet accepted the Minecraft EULA. In order to start this server you + must set eula=true inside the eula.txt file in the File Manager. +

+
+ ); +}; + +export default EulaModalFeature; diff --git a/resources/scripts/components/server/features/index.ts b/resources/scripts/components/server/features/index.ts new file mode 100644 index 000000000..2c285feb6 --- /dev/null +++ b/resources/scripts/components/server/features/index.ts @@ -0,0 +1,11 @@ +import { lazy } from 'react'; + +/** + * Custom features should be registered here as lazy components so that they do + * not impact the generated JS bundle size. They will be automatically loaded in + * whenever they are actually loaded for the client (which may be never, depending + * on the feature and the egg). + */ +const EulaModalFeature = lazy(() => import(/* webpackChunkName: "feature.eula" */'@feature/eula/EulaModalFeature')); + +export { EulaModalFeature }; diff --git a/tsconfig.json b/tsconfig.json index 41a4286b9..4b14bec71 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,11 +11,17 @@ "esModuleInterop": true, "sourceMap": true, "baseUrl": ".", - "lib": ["es2015", "dom"], + "lib": [ + "es2015", + "dom" + ], "importsNotUsedAsValues": "preserve", "paths": { "@/*": [ "./resources/scripts/*" + ], + "@feature/*": [ + "./resources/scripts/components/server/features/*" ] }, "plugins": [ @@ -23,7 +29,9 @@ "name": "typescript-plugin-tw-template" } ], - "typeRoots": ["node_modules/@types"] + "typeRoots": [ + "node_modules/@types" + ] }, "include": [ "./resources/scripts/**/*" diff --git a/webpack.config.js b/webpack.config.js index 492c74bf9..ec81a8860 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -63,6 +63,7 @@ module.exports = { extensions: ['.ts', '.tsx', '.js', '.json'], alias: { '@': path.join(__dirname, '/resources/scripts'), + '@feature': path.join(__dirname, '/resources/scripts/components/server/features'), }, symlinks: false, },