Skip to content

Commit

Permalink
Added blob pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
SIsilicon committed Mar 21, 2024
1 parent 650bbf8 commit ceebfe5
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/library/Minecraft.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { world, system, PlayerSpawnAfterEvent, WatchdogTerminateReason } from "@
import { shutdownTimers } from "./utils/scheduling.js";
import { shutdownThreads } from "./utils/multithreading.js";
import { contentLog, RawText } from "./utils/index.js";
import "./extensions/index.js";

// eslint-disable-next-line prefer-const
let _server: ServerBuild;
Expand Down
1 change: 1 addition & 0 deletions src/library/extensions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import "./string";
14 changes: 14 additions & 0 deletions src/library/extensions/string.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
interface String {
hashCode(): number;
}

String.prototype.hashCode = function () {
let hash = 0;
for (let i = 0; i < this.length; i++) {
const char = this.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash |= 0; // Convert to 32-bit integer
}
return hash;
};
4 changes: 4 additions & 0 deletions src/library/utils/vector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ export class Vector {
return new Vector(this.x + x, this.y + y, this.z + z);
}

distanceTo(v: anyVec) {
return this.sub(v).length;
}

add(v: anyVec | number) {
if (typeof v == "number") {
return new Vector(this.x + v, this.y + v, this.z + v);
Expand Down
2 changes: 1 addition & 1 deletion src/server/modules/block_parsing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ export function throwTokenError(token: Token): never {
isSyntaxError: true,
idx: -1,
start: token.pos,
end: token.pos + token.text.length,
end: token.pos + token.text.length - 1,
stack: contentLog.stack(),
};
throw err;
Expand Down
111 changes: 100 additions & 11 deletions src/server/modules/pattern.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export class Pattern implements CustomArgType {
block.setPermutation(this.block.getPermutation(block, this.context));
return !oldBlock.matches(block.typeId);
} catch (err) {
//contentLog.error(err);
// console.error(err);
return false;
}
}
Expand Down Expand Up @@ -234,15 +234,16 @@ export class Pattern implements CustomArgType {
let offset = Vector.ZERO;
if (tokens.peek()?.value == "@") {
tokens.next();
if (tokens.next().value != "[") {
throwTokenError(tokens.curr());
}
if (tokens.next().value != "[") throwTokenError(tokens.curr());
const array = parseNumberList(tokens, 3);
offset = Vector.from(array as [number, number, number]);
}
out.push(new ClipboardPattern(nodeToken(), offset.floor()));
} else if (t.value == "hand") {
out.push(new HandPattern(nodeToken()));
} else if (t.value.match?.(/blob[1-9][0-9]*/)) {
if (tokens.peek()?.value != "(") throwTokenError(tokens.peek());
processOps(out, ops, new BlobPattern(nodeToken(), Number.parseInt((<string>t.value).slice(4))));
} else {
throwTokenError(t);
}
Expand Down Expand Up @@ -319,6 +320,7 @@ export class Pattern implements CustomArgType {
}
}

type NodeJSON = { type: string; nodes: NodeJSON[] };
abstract class PatternNode implements AstNode {
public nodes: PatternNode[] = [];
abstract readonly prec: number;
Expand All @@ -330,14 +332,25 @@ abstract class PatternNode implements AstNode {

// eslint-disable-next-line @typescript-eslint/no-empty-function
postProcess() {}

/** Debug only! Not all important data is represented. */
toJSON(): NodeJSON {
return {
type: this.constructor.name,
nodes: this.nodes.map((n) => n.toJSON()),
};
}
}

class BlockPattern extends PatternNode {
readonly prec = -1;
readonly opCount = 0;
readonly permutation: BlockPermutation;

constructor(token: Token, public block: parsedBlock) {
constructor(
token: Token,
public block: parsedBlock
) {
super(token);
this.permutation = parsedBlock2BlockPermutation(block);
}
Expand All @@ -353,7 +366,10 @@ class TypePattern extends PatternNode {
readonly permutation: BlockPermutation;
readonly props: Record<string, string | number | boolean>;

constructor(token: Token, public type: string) {
constructor(
token: Token,
public type: string
) {
super(token);
this.permutation = BlockPermutation.resolve(type);
this.props = this.permutation.getAllStates();
Expand All @@ -372,7 +388,10 @@ class StatePattern extends PatternNode {
readonly prec = -1;
readonly opCount = 0;

constructor(token: Token, public states: parsedBlock["states"]) {
constructor(
token: Token,
public states: parsedBlock["states"]
) {
super(token);
}

Expand All @@ -391,7 +410,10 @@ class RandStatePattern extends PatternNode {
readonly opCount = 0;
readonly permutations: BlockPermutation[];

constructor(token: Token, public block: string) {
constructor(
token: Token,
public block: string
) {
super(token);
this.permutations = Array.from(Server.block.iteratePermutations(this.block));
}
Expand All @@ -405,7 +427,10 @@ class ClipboardPattern extends PatternNode {
readonly prec = -1;
readonly opCount = 0;

constructor(token: Token, public offset: Vector3) {
constructor(
token: Token,
public offset: Vector3
) {
super(token);
}

Expand Down Expand Up @@ -442,7 +467,11 @@ class GradientPattern extends PatternNode {

private ctxCardinal: Cardinal;

constructor(token: Token, public gradientId: string, public cardinal?: Cardinal) {
constructor(
token: Token,
public gradientId: string,
public cardinal?: Cardinal
) {
super(token);
if (cardinal) this.updateDirectionParams(cardinal);
}
Expand Down Expand Up @@ -480,7 +509,10 @@ class PercentPattern extends PatternNode {
readonly prec = 2;
readonly opCount = 1;

constructor(token: Token, public percent: number) {
constructor(
token: Token,
public percent: number
) {
super(token);
}

Expand All @@ -489,6 +521,63 @@ class PercentPattern extends PatternNode {
}
}

class BlobPattern extends PatternNode {
readonly prec = -1;
readonly opCount = 1;

private readonly offsets: Vector[] = [];
private readonly perms: { [key: number]: BlockPermutation } = {};
private readonly points: { [key: number]: Vector } = {};

constructor(
token: Token,
public readonly size: number
) {
super(token);
this.offsets = [];
for (let z = -1; z <= 1; z++) {
for (let y = -1; y <= 1; y++) {
for (let x = -1; x <= 1; x++) {
this.offsets.push(new Vector(x * this.size, y * this.size, z * this.size));
}
}
}
}

postProcess() {
this.nodes[0].postProcess();
}

getPermutation(block: BlockUnit, context: patternContext): BlockPermutation {
const blockLoc = Vector.from(block.location);
const cellLoc = blockLoc.div(this.size).floor().mul(this.size);
let closestCell = 0;
let minDist = Infinity;
for (const offset of this.offsets) {
const loc = cellLoc.add(offset);
const neighbour = this.getCellKey(loc);
if (!(neighbour in this.points)) this.points[neighbour] = new Vector(this.randomNum(), this.randomNum(), this.randomNum());

const distance = loc.add(this.points[neighbour]).distanceTo(blockLoc);
if (distance < minDist) {
closestCell = neighbour;
minDist = distance;
}
}

if (!(closestCell in this.perms)) this.perms[closestCell] = this.nodes[0].getPermutation(block, context);
return this.perms[closestCell];
}

private getCellKey(location: Vector3) {
return `${Math.floor(location.x / this.size)} ${Math.floor(location.y / this.size)} ${Math.floor(location.z / this.size)}`.hashCode();
}

private randomNum() {
return Math.random() * (this.size - 1);
}
}

class ChainPattern extends PatternNode {
readonly prec = 1;
readonly opCount = 2;
Expand Down

0 comments on commit ceebfe5

Please sign in to comment.