Skip to content

Commit

Permalink
feat: support cactbot timeline net sync translate
Browse files Browse the repository at this point in the history
  • Loading branch information
MaikoTan committed Feb 27, 2024
1 parent aa99e77 commit 3a17eba
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 65 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@
}
},
"devDependencies": {
"@babel/core": "^7.23.6",
"@babel/cli": "^7.23.4",
"@babel/core": "^7.23.6",
"@babel/generator": "^7.23.0",
"@babel/plugin-transform-typescript": "^7.22.11",
"@babel/preset-env": "^7.23.5",
Expand Down
158 changes: 94 additions & 64 deletions src/timeline/translate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,64 +19,72 @@ const extractReplacements = async (triggerPath: string): Promise<TimelineReplace

const fileContent = await readFile(triggerPath, 'utf8')

ts.transform(ts.createSourceFile(triggerPath, fileContent, ts.ScriptTarget.ES2022, true, ts.ScriptKind.TS), [(ctx: ts.TransformationContext) => (rootNode) => {
function visit(node: ts.Node): ts.Node {
if (ts.isObjectLiteralExpression(node)) {
const properties = node.properties
const timelineReplaceNode = properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'timelineReplace'
})
if (timelineReplaceNode && ts.isPropertyAssignment(timelineReplaceNode)) {
const timelineReplace = timelineReplaceNode.initializer
if (ts.isArrayLiteralExpression(timelineReplace)) {
const timelineReplaceList: TimelineReplacement[] = []
for (const element of timelineReplace.elements) {
if (ts.isObjectLiteralExpression(element)) {
const localeNode = element.properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'locale'
})
const replaceSyncNode = element.properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'replaceSync'
}) as ts.PropertyAssignment | undefined
const replaceTextNode = element.properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'replaceText'
}) as ts.PropertyAssignment | undefined
if (localeNode && ts.isPropertyAssignment(localeNode) && ts.isStringLiteral(localeNode.initializer)) {
const locale = localeNode.initializer.text as keyof LocaleText
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-inner-declarations
function resolveSync(node: ts.Node | undefined): TimelineReplacement['replaceSync'] | undefined {
if (!node) {
return
}
if (!ts.isObjectLiteralExpression(node)) {
return
}
const syncs = node.properties.map((property) => {
if (ts.isPropertyAssignment(property) && ts.isStringLiteral(property.name) && ts.isStringLiteral(property.initializer)) {
return [property.name.text, property.initializer.text]
ts.transform(ts.createSourceFile(triggerPath, fileContent, ts.ScriptTarget.ES2022, true, ts.ScriptKind.TS), [
(ctx: ts.TransformationContext) => (rootNode) => {
function visit(node: ts.Node): ts.Node {
if (ts.isObjectLiteralExpression(node)) {
const properties = node.properties
const timelineReplaceNode = properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'timelineReplace'
})
if (timelineReplaceNode && ts.isPropertyAssignment(timelineReplaceNode)) {
const timelineReplace = timelineReplaceNode.initializer
if (ts.isArrayLiteralExpression(timelineReplace)) {
const timelineReplaceList: TimelineReplacement[] = []
for (const element of timelineReplace.elements) {
if (ts.isObjectLiteralExpression(element)) {
const localeNode = element.properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'locale'
})
const replaceSyncNode = element.properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'replaceSync'
}) as ts.PropertyAssignment | undefined
const replaceTextNode = element.properties.find((property) => {
return ts.isPropertyAssignment(property) && property.name.getText() === 'replaceText'
}) as ts.PropertyAssignment | undefined
if (localeNode && ts.isPropertyAssignment(localeNode) && ts.isStringLiteral(localeNode.initializer)) {
const locale = localeNode.initializer.text as keyof LocaleText
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-inner-declarations
function resolveSync(node: ts.Node | undefined): TimelineReplacement['replaceSync'] | undefined {
if (!node) {
return
}
}).filter((sync): sync is [string, string] => !!sync)

return Object.fromEntries(syncs)
if (!ts.isObjectLiteralExpression(node)) {
return
}
const syncs = node.properties
.map((property) => {
if (
ts.isPropertyAssignment(property) &&
ts.isStringLiteral(property.name) &&
ts.isStringLiteral(property.initializer)
) {
return [property.name.text, property.initializer.text]
}
})
.filter((sync): sync is [string, string] => !!sync)

return Object.fromEntries(syncs)
}
timelineReplaceList.push({
locale,
replaceSync: resolveSync(replaceSyncNode?.initializer),
replaceText: resolveSync(replaceTextNode?.initializer),
})
}
timelineReplaceList.push({
locale,
replaceSync: resolveSync(replaceSyncNode?.initializer),
replaceText: resolveSync(replaceTextNode?.initializer),
})
}
}
ret.push(...timelineReplaceList)
}
ret.push(...timelineReplaceList)
}
}
}

return ts.visitEachChild(node, visit, ctx)
}
return ts.visitEachChild(node, visit, ctx)
}

return ts.visitNode(rootNode, visit)
}])
return ts.visitNode(rootNode, visit)
},
])

return ret
}
Expand Down Expand Up @@ -166,28 +174,50 @@ export class TranslatedTimelineProvider implements TextDocumentContentProvider {
replacedSyncKey = this.replaceCommonKey(replacedSyncKey, commonReplace, 'sync', locale)
replacedLine = replacedLine.replace(
syncMatched[0],
[
syncMatched.groups?.keyword,
'/',
replacedSyncKey,
'/',
].join(''),
[syncMatched.groups?.keyword, '/', replacedSyncKey, '/'].join(''),
)
}

// match "xxxx.x \"xxxx\""
const textMatched = /^(?<time>\d+(\.\d)?\s*)"(?<text>.*)(?<!\\)"/.exec(line)
const matchLogTypeByName = ['AddedCombatant', 'RemovedCombatant']
const matchLogTypeSource = [
'StartsUsing',
'Ability',
'NetworkAOEAbility',
'NetworkCancelAbility',
'NetworkDoT',
'WasDefeated',
]
const matchLogType = [...matchLogTypeByName, ...matchLogTypeSource, 'GameLog']
// match net sync like `Action { id: "xxxx" }`
const netSyncMatched = new RegExp(`(?<keyword>${matchLogType.join('|')})\\s*\\{(?<fields>.*)\\}`).exec(line)
if (netSyncMatched) {
const fields = netSyncMatched.groups?.fields
if (fields) {
replacedLine = replacedLine.replace(
netSyncMatched[0],
[
netSyncMatched.groups?.keyword,
' {',
this.replaceCommonKey(
this.replaceKey(fields, replace.replaceSync ?? {}, true),
commonReplace,
'sync',
locale,
),
'}',
].join(''),
)
}
}

// match "xxxx.x label \"xxxx\""
const textMatched = /^(?<time>\d+(\.\d)?\s*)(?<label>label\s*)?"(?<text>.*)(?<!\\)"/.exec(line)
if (textMatched && replace.replaceText) {
let replacedTextKey = this.replaceKey(textMatched.groups?.text as string, replace.replaceText, false)
replacedTextKey = this.replaceCommonKey(replacedTextKey, commonReplace, 'text', locale)
replacedLine = replacedLine.replace(
textMatched[0],
[
textMatched.groups?.time,
'"',
replacedTextKey,
'"',
].join(''),
[textMatched.groups?.time, textMatched.groups?.label ?? '', '"', replacedTextKey, '"'].join(''),
)
}
} catch (err) {
Expand Down Expand Up @@ -348,4 +378,4 @@ export async function exist(path: string): Promise<boolean> {
} catch {
return false
}
}
}

0 comments on commit 3a17eba

Please sign in to comment.