import React, { useEffect, useState } from "react"; import { BaseWebPlugin, notifyErrorHandler } from "@clusterio/web_ui"; import { Button, Form, Input, Spin, Typography } from "antd"; import "./style.css"; const { Paragraph, Text } = Typography; interface LoginFormProps { setToken(token: string): void, } function LoginForm(props: LoginFormProps) { let [servers, setServers] = useState(null); let [playerCode, setPlayerCode] = useState(null); let [playerCodeError, setPlayerCodeError] = useState(null); let [verifyCode, setVerifyCode] = useState(); let [verifyToken, setVerifyToken] = useState(null); useEffect(() => { (async () => { let response = await fetch(`${webRoot}api/player_auth/servers`); if (response.ok) { setServers(await response.json()); } else { setServers([]); } })(); }, []); useEffect(() => { if (verifyToken) { let checkLoop = setInterval(() => { (async () => { let response = await fetch(`${webRoot}api/player_auth/verify`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ verify_token: verifyToken, verify_code: verifyCode, player_code: playerCode, }), }); if (!response.ok) { throw new Error(`Bad server response: ${response.status}`); } let json = await response.json(); if (json.error) { // While there are other possibilites the most likely // cause of an error response here is that the code expired. setPlayerCodeError("Code expired"); setVerifyToken(null); clearInterval(checkLoop); return; } if (json.verified) { props.setToken(json.token); } })().catch(err => { clearInterval(checkLoop); notifyErrorHandler("Error verifying code")(err); }); }, 2000); return () => { clearInterval(checkLoop); }; } return undefined; }, [verifyToken]); if (!servers) { return ; } if (servers.length === 0) { return There are no servers in the cluster currently running that can complete the login via Factorio. Please try again later. ; } return <> Login using your Factorio account is a 3 step process:
  1. Start Factorio, join one of the following multiplayer servers and type /web-login into the chat:
      {servers.map(text =>
    • {text}
    • )}
  2. Enter the code displayed in the in-game dialog here:
    { (async () => { let response = await fetch(`${webRoot}api/player_auth/player_code`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ player_code: values.player_code, }), }); if (!response.ok) { throw new Error(`Bad server response: ${response.status}`); } let json = await response.json(); if (json.error) { setPlayerCodeError("Invalid Code"); setVerifyToken(null); return; } setPlayerCodeError(null); setPlayerCode(values.player_code); setVerifyCode(json.verify_code); setVerifyToken(json.verify_token); })().catch(notifyErrorHandler("Error verifying code")); }} >
  3. Enter this code into the in-game dialog:
; } export class WebPlugin extends BaseWebPlugin { async init() { this.logger.info("Player Auth init"); this.loginForms = [{ name: "player_auth.factorio", title: "Factorio", Component: LoginForm, }]; } }