Skip to content

Commit

Permalink
data modify ... from string Added
Browse files Browse the repository at this point in the history
  • Loading branch information
MulverineX committed Jan 22, 2023
1 parent e0508c9 commit 6e60e12
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 45 deletions.
45 changes: 45 additions & 0 deletions src/commands/implementations/DataCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,15 @@ export class DataModifyValues extends Command {
@command(['from', 'storage'])
private fromStorage = (...args: unknown[]) => { }

@command(['from', 'string', 'block'], { parsers: { '0': coordinatesParser } })
private fromStringBlock = (...args: unknown[]) => { }

@command(['from', 'string', 'entity'])
private fromStringEntity = (...args: unknown[]) => { }

@command(['from', 'string', 'storage'])
private fromStringStorage = (...args: unknown[]) => { }

from: {
/**
* Modify with the NBT of a block at the given position.
Expand Down Expand Up @@ -114,6 +123,42 @@ export class DataModifyValues extends Command {
storage: this.fromStorage,
}

fromString: {
/**
* Modify with the NBT String of a block at the given position.
*
* @param sourcePosition The coordinates of the block to modify the NBT with.
* @param sourcePath The path of the NBT to modify with.
* @param start Optional. Index of first character to include at the start of the string.
* @param end Optional. Index of the first character to exclude at the end of the string
*/
block: (sourcePosition: Coordinates, sourcePath: string, start?: number, end?: number) => void

/**
* Modify with the NBT String of a given entity.
*
* @param source The entity to modify the NBT with.
* @param sourcePath The path of the NBT to modify with.
* @param start Optional. Index of first character to include at the start of the string.
* @param end Optional. Index of the first character to exclude at the end of the string
*/
entity: (source: SingleEntityArgument, sourcePath: string, start?: number, end?: number) => void

/**
* Modify with the NBT String of a given storage path.
*
* @param source The storage path to modify the NBT with.
* @param sourcePath The path of the NBT to modify with.
* @param start Optional. Index of first character to include at the start of the string.
* @param end Optional. Index of the first character to exclude at the end of the string
*/
storage: (source: string, sourcePath: string, start?: number, end?: number) => void
} = {
block: this.fromStringBlock,
entity: this.fromStringEntity,
storage: this.fromStringStorage,
}

/**
* Modify the NBT with the given value.
*/
Expand Down
13 changes: 9 additions & 4 deletions src/datapack/Datapack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import type {
} from '@resources'
import type { CustomResourceInstance } from '@resources/Custom'
import type { ObjectiveInstance, SelectorCreator, SelectorProperties } from '@variables'
import type { DATA_TARGET, DATA_TYPES } from '@variables/Data'
import type { DATA_SOURCES, DATA_TARGET, DATA_TYPES } from '@variables/Data'
import type { Score } from '@variables/Score'
import type { BasePathInstance, BasePathOptions } from './BasePath'
import type { CommandArgs } from './minecraft'
Expand Down Expand Up @@ -597,11 +597,16 @@ export default class Datapack {

Selector: SelectorCreator = ((target: '@s' | '@p' | '@a' | '@e' | '@r', properties: SelectorProperties<false, false>) => new SelectorClass(this.commandsRoot, target, properties)) as any

Data = <TYPE extends DATA_TYPES, TARGET extends DATA_TARGET[TYPE] | undefined = undefined>(type: TYPE, target?: TARGET): TARGET extends undefined ? TargetlessDataInstance<TYPE> : DataInstance<TYPE> => {
Data = <
TYPE extends DATA_TYPES, SOURCE extends DATA_SOURCES,
TARGET extends DATA_TARGET[TYPE] | undefined = undefined
>(type: TYPE, source?: SOURCE, target?: TARGET): TARGET extends undefined ? TargetlessDataInstance<TYPE, SOURCE> : DataInstance<TYPE, SOURCE> => {
if (target) {
return new DataInstance(this, type, target!) as any
// eslint-disable-next-line no-unneeded-ternary, @typescript-eslint/no-non-null-assertion
return new DataInstance(this, type, source ? source : 'default', target!) as any
}
return new TargetlessDataInstance(this, type) as any
// eslint-disable-next-line no-unneeded-ternary
return new TargetlessDataInstance(this, type, source ? source : 'default') as any
}

/** A BasePath changes the base namespace & directory of nested resources. */
Expand Down
147 changes: 106 additions & 41 deletions src/variables/Data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ export type DATA_TARGET = {
'storage': string,
}

export type DATA_SOURCES = 'default' | 'string'

type DATA_PATH = string | Record<string, NBTObject> | NBTObject[]

function pathToString(path: DATA_PATH[]) {
Expand All @@ -36,49 +38,58 @@ function pathToString(path: DATA_PATH[]) {
return result
}

export class TargetlessDataInstance<TYPE extends DATA_TYPES = DATA_TYPES> {
export class TargetlessDataInstance<TYPE extends DATA_TYPES = DATA_TYPES, SOURCE extends DATA_SOURCES = DATA_SOURCES> {
protected datapack

type: TYPE

constructor(datapack: Datapack, type: TYPE) {
source: SOURCE

constructor(datapack: Datapack, type: TYPE, source: SOURCE) {
this.datapack = datapack
this.type = type
this.source = source
}

target = (target: DATA_TARGET[TYPE]) => new DataInstance(this.datapack, this.type, target)
target = (target: DATA_TARGET[TYPE]) => new DataInstance(this.datapack, this.type, this.source, target)

select = (...path: DATA_PATH[]) => new TargetlessDataPointInstance(this.datapack, this.type, path)
select = (...path: DATA_PATH[]) => new TargetlessDataPointInstance(this.datapack, this.type, this.source, path)
}

export class TargetlessDataPointInstance<TYPE extends DATA_TYPES = DATA_TYPES> {
export class TargetlessDataPointInstance<TYPE extends DATA_TYPES = DATA_TYPES, SOURCE extends DATA_SOURCES = DATA_SOURCES> {
protected datapack

type: TYPE

source: SOURCE

path

constructor(datapack: Datapack, type: TYPE, path: DATA_PATH[]) {
constructor(datapack: Datapack, type: TYPE, source: SOURCE, path: DATA_PATH[]) {
this.datapack = datapack
this.type = type
this.source = source
this.path = pathToString(path)
}

target = (target: DATA_TARGET[TYPE]) => new DataPointInstance(this.datapack, this.type, target, [this.path])
target = (target: DATA_TARGET[TYPE]) => new DataPointInstance(this.datapack, this.type, this.source, target, [this.path])

select = (...path: DATA_PATH[]) => new TargetlessDataPointInstance(this.datapack, this.type, [this.path, ...path])
select = (...path: DATA_PATH[]) => new TargetlessDataPointInstance(this.datapack, this.type, this.source, [this.path, ...path])
}

export class DataInstance<TYPE extends DATA_TYPES = DATA_TYPES> {
export class DataInstance<TYPE extends DATA_TYPES = DATA_TYPES, SOURCE extends DATA_SOURCES = DATA_SOURCES> {
datapack

type: TYPE

source: SOURCE

currentTarget: DATA_TARGET[TYPE]

constructor(datapack: Datapack, type: TYPE, target: DATA_TARGET[TYPE]) {
constructor(datapack: Datapack, type: TYPE, source: SOURCE, target: DATA_TARGET[TYPE]) {
this.datapack = datapack
this.type = type
this.source = source
this.currentTarget = target
}

Expand All @@ -89,70 +100,124 @@ export class DataInstance<TYPE extends DATA_TYPES = DATA_TYPES> {
this.datapack.commandsRoot.data.merge[this.type](this.currentTarget as any, value)
}

target = (target: DATA_TARGET[TYPE]) => new DataInstance(this.datapack, this.type, target)
target = (target: DATA_TARGET[TYPE]) => new DataInstance(this.datapack, this.type, this.source, target)

select = (...path: DATA_PATH[]) => new DataPointInstance(this.datapack, this.type, this.currentTarget, path)
select = (...path: DATA_PATH[]) => new DataPointInstance(this.datapack, this.type, this.source, this.currentTarget, path)

toString = () => this.currentTarget

toJSON = this.toString
}

export class DataPointInstance<TYPE extends DATA_TYPES = any> extends ConditionTextComponentClass {
type sliceType = {
/**
* Optional. Index of first character to include at the start of the string.
*/
start?: number,
/**
* Optional. Index of the first character to exclude at the end of the string.
*/
end?: number
}

type scaleType = {type: StoreType, scale?: number}

export class DataPointInstance<TYPE extends DATA_TYPES = any, SOURCE extends DATA_SOURCES = any> extends ConditionTextComponentClass {
datapack

type: TYPE

source: SOURCE

path

currentTarget: DATA_TARGET[TYPE]

constructor(datapack: Datapack, type: TYPE, target: DATA_TARGET[TYPE], path: DATA_PATH[]) {
constructor(datapack: Datapack, type: TYPE, source: SOURCE, target: DATA_TARGET[TYPE], path: DATA_PATH[]) {
super()
this.datapack = datapack
this.type = type
this.source = source
this.path = pathToString(path)

this.currentTarget = target
}

target = (target: DATA_TARGET[TYPE]) => new DataPointInstance(this.datapack, this.type, target, [this.path])
target = (target: DATA_TARGET[TYPE]) => new DataPointInstance(this.datapack, this.type, this.source, target, [this.path])

select = (...path: DATA_PATH[]) => new DataPointInstance(this.datapack, this.type, this.currentTarget, [this.path, ...path])
select = (...path: DATA_PATH[]) => new DataPointInstance(this.datapack, this.type, this.source, this.currentTarget, [this.path, ...path])

protected modify = (cb: (data: DataModifyType) => DataModifyValues, value: NBTObject | DataPointInstance) => {
const data = cb(this.datapack.commandsRoot.data.modify[this.type](this.currentTarget as any, this.path))
protected modify = (cb: (data: DataModifyType) => DataModifyValues, value: NBTObject | DataPointInstance, sliceString?: [number] | [number, number]) => {
if (this.source === 'default') {
const data = cb(this.datapack.commandsRoot.data.modify[this.type](this.currentTarget as any, this.path))

// The value is another Data Point
if (value instanceof DataPointInstance) {
data.from[value.type as DATA_TYPES](value.currentTarget as any, value.path)
return
}
// The value is another Data Point
if (value instanceof DataPointInstance) {
data.from[value.type as DATA_TYPES](value.currentTarget as any, value.path)
return
}

// The value is a NBT
data.value(value)
}
// The value is a NBT
data.value(value)
} else {
const data = cb(this.datapack.commandsRoot.data.modify[this.type](this.currentTarget as any, this.path))

protected executeStore = (storeType: StoreType, scale: number) => this.datapack.commandsRoot.execute.store.result[this.type](this.currentTarget as any, this.path, storeType as StoreType, scale)
// The value is another Data Point
if (value instanceof DataPointInstance) {
if (sliceString) {
data.fromString[value.type as DATA_TYPES](value.currentTarget as any, value.path, ...sliceString)
return
}

set: (
/**
* Set the data point to the given NBT.
*/
((value: NBTObject | DataPointInstance) => void) &

/**
* Set the data point to the given score, with a given type and a scale.
*/
((value: Score, storeType: StoreType, scale?: number) => void)
) = (value: NBTObject | DataPointInstance | Score, storeType?: StoreType, scale: number = 1) => {
if (value instanceof Score) {
this.executeStore(storeType as StoreType, scale).run.scoreboard.players.get(value.target, value.objective)
data.fromString[value.type as DATA_TYPES](value.currentTarget as any, value.path)
return
}

this.modify((data) => data.set, value)
// The value is a NBT
data.value(value)
}
}

protected executeStore = (storeType: StoreType, scale: number) => this.datapack.commandsRoot.execute.store.result[this.type](this.currentTarget as any, this.path, storeType as StoreType, scale)

/**
* Set the data point to the given NBT.
*/
set(value: NBTObject): void

/**
* Set the data point to the given data point.
* @param value A non-string data point.
*/
set(value: DataPointInstance<DATA_TYPES, 'default'>): void

/**
* Set the data point to the given data point string.
* @param value A string data point.
* @param slice Optional. Where to slice the string.
*/
set(value: DataPointInstance<DATA_TYPES, 'string'>, slice?: sliceType): void

/**
* Set the data point to the given score, with a given type & scale.
* @param value A score.
* @param typeAndScale Number type & scale that will default to 1.
*/
set(value: Score, typeAndScale: scaleType): void

set(value: NBTObject | DataPointInstance<DATA_TYPES, 'default'> | DataPointInstance<DATA_TYPES, 'string'> | Score, sliceOrScale?: sliceType | scaleType): void {
if (value instanceof Score && sliceOrScale) {
this.executeStore((sliceOrScale as scaleType).type, (sliceOrScale as scaleType).scale || 1).run.scoreboard.players.get(value.target, value.objective)
} else if (sliceOrScale === undefined) {
this.modify((data) => data.set, value as DataPointInstance)
} else {
this.modify(
(data) => data.set,
value as DataPointInstance,
(sliceOrScale as sliceType).end ? [(sliceOrScale as sliceType).start as number || 0, (sliceOrScale as sliceType).end as number] : [(sliceOrScale as sliceType).start as number],
)
}
}

/**
* Set the data point to the given NBT.
Expand Down

0 comments on commit 6e60e12

Please sign in to comment.