Skip to content

Commit

Permalink
Merge pull request #11 from misprit7/color-pixel-box
Browse files Browse the repository at this point in the history
Color Pixel Boxes
  • Loading branch information
misprit7 authored Jul 11, 2024
2 parents c42120f + 838e213 commit 7de2845
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 33 deletions.
158 changes: 125 additions & 33 deletions Accelerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ internal static class Accelerator
// is checking the same tile so for data locality it makes sense to do it this way
public static int[,,] wireGroup;

// Indexed by group to contain what color each group is
public static int[] groupColor;

// Copy of which wires are at each tile in a more usable form
// Entries are bitmasks of 1<<color
// i.e. red = 1, blue = 2, green = 4, yellow = 8
Expand Down Expand Up @@ -175,7 +178,8 @@ private static void RegisterTile(int x, int y, int c, int group)
// Junction boxes always have id -1
// To avoid an infinite loop we ensure we pass through them one way
// Since each junction box has exactly one entrance per channel and one exit this works
if (tile.TileType != TileID.WirePipe)
// However upon first traversal per color colored pbs get a group since we need to keep track, but this is done later
if (!IsJunction(x, y))
wireGroup[x, y, c] = group;

// Treat logic lamps specially since they mean different things based on frame
Expand Down Expand Up @@ -208,6 +212,19 @@ private static void RegisterTile(int x, int y, int c, int group)
}

}
else if (tile.TileType == Tiles.ColorPixelBox.ID){
int g = wireGroup[x, y, c];
if (g != -1 && g != group){
uint coord = xy2uint(x, y);
pixelBoxes[g][group] = coord;
pixelBoxes[group][g] = coord;
pbId2Coord.Add(coord);
// There are at most 2 traversals, so we can just reset this to -1
wireGroup[x, y, c] = -1;
} else {
wireGroup[x, y, c] = group;
}
}
else if (triggeredIDs.Contains(tile.TileType) || tile.HasActuator)
{
triggerableDict[group].Add(new Point16(x, y));
Expand All @@ -220,6 +237,11 @@ private static void RegisterTile(int x, int y, int c, int group)

/*
* Find each of the wire groups in the world recursively, used for preprocessing
*
* Note: junction boxes are handled pretty elegantly
* Since they each have at most one entrance and one exit, there's no way to make a loop
* of junction boxes while also having a stray wire to initiate a DFS
* Therefore we don't have to check if we're re-traversing a junction
*/
private static void FindGroup(int x, int y, int prevX, int prevY, int c, int group)
{
Expand All @@ -228,22 +250,15 @@ private static void FindGroup(int x, int y, int prevX, int prevY, int c, int gro

Tile tile = Main.tile[x, y];

// If we've already traversed this junction box with this group skip it
// If the junction box already has two groups skip it
// If it isn't a junction box skip it if it's been traversed before
if (tile.TileType == TileID.WirePipe)
{
// Yes there's a logical simplification here with nested ifs but the logic is clearer this way
if (wireGroup[x, y, c] == group || wireGroup[x, y, c] == 0) return;
}
else if (wireGroup[x, y, c] != -1) return;
if (!IsJunction(x, y) && wireGroup[x, y, c] != -1) return;

// Handle all registration of this tile to caches
RegisterTile(x, y, c, group);

if (tile.TileType != TileID.WirePipe)
if (!IsJunction(x, y))
{
bool prevJunction = Main.tile[prevX, prevY].TileType == TileID.WirePipe;
bool prevJunction = IsJunction(prevX, prevY);
// What 30 minutes of stackoverflow searching for marginally cleaner syntax gets you
foreach (var (dx, dy) in new (int, int)[] { (1, 0), (0, 1), (-1, 0), (0, -1) })
{
Expand All @@ -256,28 +271,41 @@ private static void FindGroup(int x, int y, int prevX, int prevY, int c, int gro
else
{
int deltaX = 0, deltaY = 0;
switch (tile.TileFrameX)
if(tile.TileType == TileID.WirePipe){
switch (tile.TileFrameX)
{
case 0: // + shape
deltaX = (x - prevX);
deltaY = (y - prevY);
break;
case 18: // // shape
deltaX = -(y - prevY);
deltaY = -(x - prevX);
break;
case 36:// \\ shape
deltaX = (y - prevY);
deltaY = (x - prevX);
break;
default:
throw new UsageException("Junction box frame didn't line up to 0, 18 or 36");
}
}
else
{
case 0: // + shape
deltaX = (x - prevX);
deltaY = (y - prevY);
break;
case 18: // // shape
deltaX = -(y - prevY);
deltaY = -(x - prevX);
break;
case 36:// \\ shape
deltaX = (y - prevY);
deltaY = (x - prevX);
break;
default:
throw new UsageException("Junction box frame didn't line up to 0, 18 or 36");
deltaX = (x - prevX);
deltaY = (y - prevY);
}

FindGroup(x + deltaX, y + deltaY, x, y, c, group);
FindGroup(x + deltaX, y + deltaY, x, y, c, group);
}
}

/*
* Checks if tile is a junction, i.e. junction box or coloredPB
*/
private static bool IsJunction(int x, int y){
return Main.tile[x, y].TileType == TileID.WirePipe || Main.tile[x, y].TileType == Tiles.ColorPixelBox.ID;
}

/*
* Checks whether a tile is the top of a standard gate
*/
Expand Down Expand Up @@ -308,7 +336,7 @@ private static void ToggleLamp(int x, int y)
/*
* Toggles a pixel box
*/
private static void TogglePixelBox(int x, int y)
private static void TogglePb(int x, int y)
{
Tile tile = Main.tile[x, y];
if (tile.TileFrameX == 0) tile.TileFrameX = 18;
Expand All @@ -319,6 +347,37 @@ private static void TogglePixelBox(int x, int y)
}
}

/*
* Toggles a colored pixel box
* cMask: bitmask of which colors to toggle
*/
private static void ToggleColoredPb(int x, int y, int cMask)
{
Tile tile = Main.tile[x, y];

int state = (tile.TileFrameX / 18) + (((tile.TileFrameY / 18)) << 2);
// Toggles cth bit
state ^= cMask;
/*Main.NewText($"State: {state}, x: {tile.TileFrameX}, y: {tile.TileFrameY}, cMask: {cMask}");*/
SetColoredPb(x, y, (byte)state);

}

/*
* Sets colored pb to a specified state
*/
private static void SetColoredPb(int x, int y, byte state)
{
Tile tile = Main.tile[x, y];

tile.TileFrameX = (short)(18 * (0b0011 & state));
tile.TileFrameY = (short)(18 * ((0b1100 & state) >> 2));
if (Main.netMode == NetmodeID.Server)
{
NetMessage.SendTileSquare(-1, x, y);
}
}

/*
* Hit a single wire
*/
Expand Down Expand Up @@ -497,7 +556,13 @@ public static void HitWire(DoubleStack<Point16> next, int wireType)
if (pixelBoxes[group].ContainsKey((g)))
{
Point16 point = uint2Point(pixelBoxes[group][g]);
TogglePixelBox(point.X, point.Y);
if(Main.tile[point.X, point.Y].TileType == TileID.PixelBox){
TogglePb(point.X, point.Y);
} else if(Main.tile[point.X, point.Y].TileType == Tiles.ColorPixelBox.ID){
if(groupColor[group] == groupColor[g]){
ToggleColoredPb(point.X, point.Y, 1 << (colors - 1 - groupColor[g]));
}
}
}
}
}
Expand Down Expand Up @@ -607,6 +672,7 @@ public static void Preprocess()

int group = 0;
numGroups = 1 << 10;
groupColor = new int[numGroups];
groupState = new bool[numGroups];
groupOutOfSync = new bool[numGroups];
pixelBoxes = new Dictionary<int, uint>[numGroups];
Expand All @@ -618,15 +684,17 @@ public static void Preprocess()
{
if (wireGroup[x, y,c] == -1 &&
(wireCache[x, y] & (1<<c)) != 0 &&
Main.tile[x, y].TileType != TileID.WirePipe)
!IsJunction(x, y))
{
if(group >= numGroups)
{
numGroups *= 2;
Array.Resize(ref groupColor, numGroups);
Array.Resize(ref groupState, numGroups);
Array.Resize(ref groupOutOfSync, numGroups);
Array.Resize(ref pixelBoxes, numGroups);
}
groupColor[group] = c;
groupState[group] = false;
groupOutOfSync[group] = false;

Expand Down Expand Up @@ -672,7 +740,9 @@ public static void Preprocess()
groupsTriggered = new int[numGroups];

// Inverts pbId2Coord to a dictionary with inverse mapping
pbCoord2Id = pbId2Coord.Select((s, i) => new { s, i }).ToDictionary(x => x.s, x => x.i);
if (!WireHead.colorPb){
pbCoord2Id = pbId2Coord.Select((s, i) => new { s, i }).ToDictionary(x => x.s, x => x.i);
}
numPb = pbId2Coord.Count();
// Hardcoded default
if(default_clock_coord.X < Main.maxTilesX && default_clock_coord.Y < Main.maxTilesY){
Expand All @@ -691,7 +761,29 @@ public static void SyncPb()
for(int i = 0; i < numPb; ++i){
if(pb_states[i] == 0) continue;
Point16 p = uint2Point(pbId2Coord[i]);
TogglePixelBox(p.X, p.Y);
TogglePb(p.X, p.Y);
}
}
}

/*
* Converts all pixel boxes in the world to either color or monochrome
*/
public static void convertPb(bool colored){
for (int x = 0; x < Main.maxTilesX; ++x)
{
for (int y = 0; y < Main.maxTilesY; ++y){
if(colored && Main.tile[x, y].TileType == TileID.PixelBox){
WorldGen.KillTile(x, y, noItem: true);
WorldGen.PlaceTile(x, y, Tiles.ColorPixelBox.ID, forced: true, mute: true);
/*WorldGen.ReplaceTile(x, y, (ushort) coloredPbID, 0);*/
Main.NewText("Replacing mono->col");
} else if(!colored && Main.tile[x, y].TileType == Tiles.ColorPixelBox.ID){
WorldGen.KillTile(x, y, noItem: true);
WorldGen.PlaceTile(x, y, TileID.PixelBox, forced: true, mute: true);
/*WorldGen.ReplaceTile(x, y, (ushort) TileID.PixelBox, 0);*/
Main.NewText("Replacing col->mono");
}
}
}
}
Expand Down
24 changes: 24 additions & 0 deletions Commands/AccelCommand.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using Terraria;
using Terraria.ModLoader;

namespace WireHead.Commands
Expand All @@ -15,6 +16,7 @@ public static void Exec(string[] args)
WireHead.toExec.Enqueue(() => {
Accelerator.Preprocess();
Console.WriteLine("Preprocessing complete");
Main.NewText("Preprocessed");
});
break;
case "sync":
Expand All @@ -23,6 +25,7 @@ public static void Exec(string[] args)
WireHead.toExec.Enqueue(() => {
Accelerator.BringInSync(true);
Console.WriteLine("Sync complete");
Main.NewText("Synced");
});
break;
case "enable":
Expand All @@ -32,6 +35,8 @@ public static void Exec(string[] args)
{
WireHead.AddEvents();
Accelerator.Preprocess();
/*Accelerator.convertPb(WireHead.colorPb);*/
Main.NewText("WireHead enabled");
}
TerraCC.disable();
Console.WriteLine("Traditional accelerator enabled");
Expand All @@ -45,6 +50,8 @@ public static void Exec(string[] args)
Accelerator.BringInSync();
WireHead.RemoveEvents();
TerraCC.disable();
/*Accelerator.convertPb(false);*/
Main.NewText("WireHead disabled");
}
Console.WriteLine("Accelerator disabled");
});
Expand All @@ -65,6 +72,23 @@ public static void Exec(string[] args)
TerraCC.compile();
}
TerraCC.enable();
Main.NewText("World compiled");
});
break;
case "color":
case "col":
WireHead.toExec.Enqueue(() => {
if(args.Length >= 1 && args[1] == "t" || args[1] == "true" || args[1] == "e" || args[1] == "enable"){
WireHead.colorPb = true;
} else if(args.Length >= 1 && args[1] == "f" || args[1] == "false" || args[1] == "d" || args[1] == "disable"){
WireHead.colorPb = false;
} else {
WireHead.colorPb = !WireHead.colorPb;
}
if(!WireHead.vanillaWiring){
Accelerator.convertPb(WireHead.colorPb);
}
Main.NewText((WireHead.colorPb ? "Enabled" : "Disabled") + " colored pixel boxes");
});
break;
default:
Expand Down
19 changes: 19 additions & 0 deletions Items/ColorPixelBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Terraria;
using Terraria.GameContent;
using Terraria.ID;
using Terraria.ModLoader;

namespace WireHead.Items
{
public class ColorPixelBox : ModItem
{
public override void SetStaticDefaults() {
Item.ResearchUnlockCount = 25;
}

public override void SetDefaults() {
Item.DefaultToPlaceableTile(ModContent.TileType<Tiles.ColorPixelBox>());
Item.value = 750;
}
}
}
Binary file added Items/ColorPixelBox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Items/Pixel_Box.webp
Binary file not shown.
5 changes: 5 additions & 0 deletions Localization/en-US_Mods.WireHead.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,9 @@ Items: {
DisplayName: Trigger Staff
Tooltip: ""
}

ColorPixelBox: {
Tooltip: ""
DisplayName: Color Pixel Box
}
}
20 changes: 20 additions & 0 deletions Tiles/ColorPixelBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using Microsoft.Xna.Framework;
using Terraria;
using Terraria.ModLoader;
using Terraria.ObjectData;
using Terraria.ID;

namespace WireHead.Tiles
{
public class ColorPixelBox : ModTile
{
// Probably a better way to do this but it saves a bunch of typing
public static int ID = ModContent.TileType<ColorPixelBox>();
public override void SetStaticDefaults()
{

Main.tileFrameImportant[Type] = true;
AddMapEntry(new Color(200, 200, 200));
}
}
}
Binary file added Tiles/ColorPixelBox.kra
Binary file not shown.
Binary file added Tiles/ColorPixelBox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Tiles/ColorPixelBox_older.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions WireHead.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class WireHead : Mod

public static bool vanillaWiring = false;
public static bool useTerracc = false;
public static bool colorPb = !vanillaWiring;
public static ConcurrentQueue<Action> toExec = new ConcurrentQueue<Action>();

private static void UpdateConnectedClients(Terraria.On_Netplay.orig_UpdateConnectedClients orig)
Expand Down Expand Up @@ -247,6 +248,7 @@ public class WireHeadSystem : ModSystem
public override void OnWorldLoad()
{
base.OnWorldLoad();
/*Accelerator.convertPb(WireHead.colorPb);*/
}

public override void PreSaveAndQuit()
Expand Down

0 comments on commit 7de2845

Please sign in to comment.