UNPKG

mdx-m3-viewer

Version:

A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.

159 lines (125 loc) 4.55 kB
import ECA from '../../parsers/w3x/wtg/eca'; import Parameter from '../../parsers/w3x/wtg/parameter'; import SubParameters from '../../parsers/w3x/wtg/subparameters'; /** * Creates a new Custom Script or comment ECA with the given data. */ export function createCustomScriptOrCommentECA(data: string, isComment: boolean) { let eca = new ECA(); eca.type = 2; // Action if (isComment) { eca.name = 'CommentString'; } else { eca.name = 'CustomScriptCode'; } eca.isEnabled = 1; let parameter = new Parameter(); parameter.type = 3; // String parameter.value = data; eca.parameters[0] = parameter; return eca; } /** * Creates a new Custom Script ECA with the given script. */ export function createCustomScriptECA(script: string) { return createCustomScriptOrCommentECA(script, false); } // /** // * Creates a new comment ECA with the given comment. // */ // function createCommentECA(comment: string) { // return createCustomScriptOrCommentECA(comment, true); // } function subParametersToEca(subParameters: SubParameters, group: number) { let eca = new ECA(); eca.name = subParameters.name; eca.type = subParameters.type; eca.group = group; eca.isEnabled = 1; eca.parameters.push(...subParameters.parameters); return eca; } export function convertSingleToMultiple(eca: ECA) { if (eca.name === 'IfThenElse') { let parameters = eca.parameters; let ifParam = subParametersToEca(<SubParameters>parameters[0].subParameters, 0); let thenParam = subParametersToEca(<SubParameters>parameters[1].subParameters, 1); let elseParam = subParametersToEca(<SubParameters>parameters[2].subParameters, 2); eca.name = 'IfThenElseMultiple'; eca.parameters.length = 0; eca.ecas.push(ifParam, thenParam, elseParam); return true; } else if (eca.name === 'ForGroup' || eca.name === 'ForForce') { let action = subParametersToEca(<SubParameters>eca.parameters[1].subParameters, 0); eca.name = `${eca.name}Multiple`; eca.parameters.length = 1; eca.ecas.push(action); return true; } return false; } /** * Given the name of the parent of some child ECA, and the child's group, determine if it's a condition. */ export function isConditionECA(name: string, group: number) { if (group !== 0) { return false; } return name === 'AndMultiple' || name === 'OrMultiple' || name === 'IfThenElseMultiple'; } const SCRIPT_LINE_LENGTH = 239; /** * CustomScriptCode ECAs have a maximum length for their (typically) string parameter. * If the script length exceeds the maximum length, WE will fail to load the map properly. * Either it crashes, or it loads the map and GUI up until the invalid ECA, after which everything is an error. * This functions is used to split such ECAs. * Splitting is possible, because the Jass parser seems to not consider multiline comments as token delimiters. * For example, the following lines: * * call BJDebug/* * /*Msg("hi") * * When compiled result in the correct call: * * call BJDebugMsg("hi") */ export function ensureCustomScriptCodeSafety(ecas: ECA[]) { let outputEcas = []; for (let eca of ecas) { if (eca.name === 'CustomScriptCode') { let script = eca.parameters[0].value; if (script.length > SCRIPT_LINE_LENGTH) { let lines = Math.ceil(script.length / SCRIPT_LINE_LENGTH); let lastLine = lines - 1; let firstInPair = true; for (let i = 0; i < lines; i++) { let text = script.substr(i * SCRIPT_LINE_LENGTH, SCRIPT_LINE_LENGTH); if (i < lastLine) { if (firstInPair) { text = `${text}/*`; } else { text = `*/${text}`; } firstInPair = !firstInPair; } let customScript = createCustomScriptECA(text); customScript.group = eca.group; outputEcas.push(customScript); } } else { outputEcas.push(eca); } } else { outputEcas.push(eca); } } return outputEcas; } /** * Given a name, converts all of the non-ASCII characters and space characters to underlines. */ export function ensureNameSafety(name: string) { // Convert non-ASCII characters to underlines, for locales other than en. return name.split('').map((c) => c.charCodeAt(0) > 127 ? '_' : c).join('').replace(/\s/g, '_'); }