diff --git a/src/commands/implementations/entity/execute.ts b/src/commands/implementations/entity/execute.ts index 7842fbd..f1fd6f0 100644 --- a/src/commands/implementations/entity/execute.ts +++ b/src/commands/implementations/entity/execute.ts @@ -340,6 +340,8 @@ export class ExecuteIfUnlessCommand extends ExecuteComman /** Checks whether the data point exists or the targeted block, entity or storage has any data for a given tag. */ data(dataPoint: DataPointClass): void + data(): ExecuteDataArgsCommand + data(dataPoint?: DataPointClass) { if (dataPoint) { return this.nestedExecute(dataPoint._toMinecraftCondition().getCondition() as ['']) diff --git a/src/commands/implementations/server/return.ts b/src/commands/implementations/server/return.ts index 58b7d98..97e55bf 100644 --- a/src/commands/implementations/server/return.ts +++ b/src/commands/implementations/server/return.ts @@ -107,7 +107,7 @@ export class ReturnCommand extends CommandArguments { protected NodeType = ReturnCommandNode get return() { - const run = new ReturnArgumentsCommand(this.sandstonePack) + const run = new ReturnArgumentsCommand(this.sandstonePack) return makeCallable(run, (value: Macroable) => this.finalCommand([value]), true) } diff --git a/src/commands/index.ts b/src/commands/index.ts index b55222f..cfaac14 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,2 +1,3 @@ export * from './commands.js' +export * from './helpers.js' export * from './implementations/index.js' diff --git a/src/pack/visitors/containerCommandsToMCFunction.ts b/src/pack/visitors/containerCommandsToMCFunction.ts index 0a375ba..f2f3b93 100644 --- a/src/pack/visitors/containerCommandsToMCFunction.ts +++ b/src/pack/visitors/containerCommandsToMCFunction.ts @@ -1,8 +1,14 @@ /* eslint-disable dot-notation */ +import { ContainerCommandNode } from 'sandstone/core' + import { GenericSandstoneVisitor } from './visitor.js' -import type { ContainerCommandNode, MCFunctionNode } from 'sandstone/core' +import type { MCFunctionNode } from 'sandstone/core' + +// let bippity = 0 + +// let boppity = 0 /** * Transforms an execute with several nodes into an execute calling a new function. @@ -11,17 +17,24 @@ export class ContainerCommandsToMCFunctionVisitor extends GenericSandstoneVisito currentMCFunction: MCFunctionNode | null = null visitContainerCommandNode = (node_: ContainerCommandNode) => { + // console.log('bippity', bippity++) const { node, mcFunction } = node_.createMCFunction(this.currentMCFunction) if (mcFunction) { const visitedMCFunction = this.visitMCFunctionNode(mcFunction) this.core.resourceNodes.add(visitedMCFunction) + } else if (node instanceof ContainerCommandNode && node.body) { + for (const [i, child] of node.body.entries()) { + const visit = this.visit(child) + node.body.splice(i, 1, ...(Array.isArray(visit) ? visit : [visit])) + } } return Array.isArray(node) ? node.flatMap((n) => this.visit(n)) : node } visitMCFunctionNode = (node: MCFunctionNode) => { + // console.log('boppity', boppity++) const prev = this.currentMCFunction this.currentMCFunction = node diff --git a/src/pack/visitors/ifElseTransformationVisitor.ts b/src/pack/visitors/ifElseTransformationVisitor.ts index 82d2b1f..9fa2ec0 100644 --- a/src/pack/visitors/ifElseTransformationVisitor.ts +++ b/src/pack/visitors/ifElseTransformationVisitor.ts @@ -1,6 +1,6 @@ /* eslint-disable no-spaced-func */ /* eslint-disable func-call-spacing */ -import { ExecuteCommandNode, ReturnCommandNode } from 'sandstone/commands' +import { ExecuteCommandNode, ReturnCommandNode, ReturnRunCommandNode } from 'sandstone/commands' import { IfNode } from 'sandstone/flow' import { GenericSandstoneVisitor } from './visitor.js' @@ -62,7 +62,10 @@ export class IfElseTransformationVisitor extends GenericSandstoneVisitor { return new ExecuteCommandNode(this.pack, [[node.condition.getValue()]], { isSingleExecute: false, givenCallbackName: `${i}_${callbackName}`, - body: body.map((_node) => this.genericVisit(_node)), + body: [new ReturnRunCommandNode(this.pack, ['run'], { + isSingleExecute: false, + body: body.map((_node) => this.genericVisit(_node)), + })], }) } // Else node, just add the body diff --git a/src/pack/visitors/unifyChainedExecutes.ts b/src/pack/visitors/unifyChainedExecutes.ts index bc69904..54b3e22 100644 --- a/src/pack/visitors/unifyChainedExecutes.ts +++ b/src/pack/visitors/unifyChainedExecutes.ts @@ -12,9 +12,9 @@ export class UnifyChainedExecutesVisitor extends GenericSandstoneVisitor { } const chainedCommand = node.body[0] - if (chainedCommand instanceof ExecuteCommandNode) { + if (chainedCommand && chainedCommand instanceof ExecuteCommandNode) { // The chained command is an execute. - node.body = [chainedCommand.body[0]] + node.body = chainedCommand.body node.args.push(...chainedCommand.args) } diff --git a/src/variables/Score.ts b/src/variables/Score.ts index 287d8d9..7760cca 100644 --- a/src/variables/Score.ts +++ b/src/variables/Score.ts @@ -5,9 +5,9 @@ import { rangeParser } from './parsers.js' import type { COMPARISON_OPERATORS, FormattingTags, JSONTextComponent, MultipleEntitiesArgument, ObjectiveArgument, OPERATORS, Range, } from 'sandstone/arguments' +import type { FinalCommandOutput, SandstoneCommands } from 'sandstone/commands' import type { NotNode } from 'sandstone/flow' import type { ConditionClass } from 'sandstone/variables' -import type { SandstoneCommands } from '../commands/index.js' import type { SandstonePack } from '../pack/index.js' import type { ComponentClass } from './abstractClasses.js' import type { DATA_TYPES, DataPointClass } from './Data.js' @@ -613,51 +613,70 @@ export class Score extends MacroArgument implements ConditionClass, ComponentCla _toMinecraftCondition: () => new this.sandstonePack.conditions.Score(this.sandstonePack.core, [`${this.target}`, `${this.objective}`, 'matches', rangeParser(range)]), }) - match = (minimum: number, maximum: number, callback: (num: number) => void) => { - const { _ } = this.sandstonePack + match = (minimum: number, maximum: number, callback: (returnCmd: (SandstoneCommands & ((_callback: () => any) => FinalCommandOutput)), num: number) => void) => { + const { _, commands: { execute }, MCFunction } = this.sandstonePack // First, specify we didn't find a match yet - const foundMatch = this.sandstoneCore.pack.Variable(0) - const callCallback = (num: number) => { - _.if(_.and(this['=='](num), foundMatch['=='](0)), () => { - _.return.run(() => { - // If we found the correct score, call the callback & specify we found a match - callback(num) - foundMatch.set(1) - }) - }) + // If we found the correct score, call the callback & specify we found a match + callback(execute.if.score(this, 'matches', num).run.returnCmd.run, num) } - // Recursively match the score - const recursiveMatch = (min: number, max: number) => { - const diff = max - min + // I actually have no idea why this is needed, but it is + const total = maximum - minimum - 1 - if (diff < 0) { - return - } + const score = this - if (diff === 3) { - callCallback(min) - callCallback(min + 1) - callCallback(min + 2) - return - } - if (diff === 2) { - callCallback(min) - callCallback(min + 1) - return - } - if (diff === 1) { - callCallback(min) - return - } + // This is my personal hell - const mean = Math.floor((min + max) / 2) + let executeCount = 0 - _.if(this['<'](mean), () => _.return.run(() => recursiveMatch(min, mean))) - _.if(this['>='](mean), () => _.return.run(() => recursiveMatch(mean, max))) - } + function split(currentTotal: number, current: number) { + if (currentTotal > 10) { + const chunks = Math.floor(currentTotal / 10) + + if (chunks > 10) { + const _chunks = Math.floor(chunks / 10) + + const chunkSize = Math.floor(currentTotal / _chunks) + + for (let i = 0; i < _chunks; i += 1) { + const last = i === _chunks - 1 + + executeCount += 1 - recursiveMatch(minimum, maximum) + const localCurrent = current + chunkSize * i + + execute.if.score(score, 'matches', `${localCurrent}..${localCurrent + chunkSize - (last ? 0 : 1)}`).run.returnCmd.run(() => split(chunkSize, localCurrent)) + } + + executeCount += 1 + + execute.if.score(score, 'matches', `${(chunkSize * _chunks) + current}..`).run.returnCmd.run(() => split((currentTotal % chunkSize) + 1, (chunkSize * _chunks) + current)) + } else { + const chunkSize = Math.floor(currentTotal / chunks) + + if (chunkSize > 10) { + executeCount += 2 + execute.if.score(score, 'matches', `${current}..${current + 9}`).run.returnCmd.run(() => split(10, current)) + + execute.if.score(score, 'matches', `${10 + current}..`).run.returnCmd.run(() => split(currentTotal - 10, 10 + current)) + } else { + for (let i = 0; i < chunks; i += 1) { + const localCurrent = (chunkSize * i) + current + + executeCount += 1 + + execute.if.score(score, 'matches', `${localCurrent}..${localCurrent + chunkSize - 1}`).run.returnCmd.run(() => split(chunkSize, localCurrent)) + } + } + } + } + if (currentTotal !== 0 && currentTotal <= 10) { + for (let i = 0; i < currentTotal; i += 1) { + callback(execute.if.score(score, 'matches', current + i).run.returnCmd.run, current + i) + } + } + } + split(total, minimum) } }