ID:1895091
 
Easy AutoJoin()

This is a super simple auto join technique I discovered and I can't believe I didn't think of it earlier. (duhh)

It will append a code to the object's icon_state in the format of NSEW (North, South, East, West). Add this code to the states in your .dmi file and you're done.



atom/proc/AutoJoin()

icon_state = "" // Remove the icon_state used for placing it on the map

var/north = locate(type) in get_step(src,NORTH)
var/south = locate(type) in get_step(src,SOUTH)
var/east = locate(type) in get_step(src,EAST)
var/west = locate(type) in get_step(src,WEST)

icon_state += north ? "N" : ""
icon_state += south ? "S" : ""
icon_state += east ? "E" : ""
icon_state += west ? "W" : ""




If you're really optimization heavy, this works just the same twice as fast.
atom/proc/AutoJoin()
icon_state = "[(locate(type) in get_step(src,NORTH)) ? "N" : ""][(locate(type) in get_step(src,SOUTH)) ? "S" : ""][(locate(type) in get_step(src,EAST)) ? "E" : ""][(locate(type) in get_step(src,WEST)) ? "W" : ""]"
Much easier/better/faster to use bitflags in this case.

Nope. I tested it. That's fairly consistent with my experimentation with bitwise operations. On the whole they're pretty slow on BYOND.



var/list/cardinal_dirs = list(NORTH,SOUTH,EAST,WEST)

mob
verb
textJoin()
for(var/x = 0, x < 100000, x++)

icon_state = ""

var/north = locate(type) in get_step(src,NORTH)
var/south = locate(type) in get_step(src,SOUTH)
var/east = locate(type) in get_step(src,EAST)
var/west = locate(type) in get_step(src,WEST)

icon_state += north ? "N" : ""
icon_state += south ? "S" : ""
icon_state += east ? "E" : ""
icon_state += west ? "W" : ""

bitJoin()
for(var/x = 0, x < 100000, x++)

icon_state = ""
var/word = 0
for(var/d in cardinal_dirs)
word |= (locate(type) in get_step(src,d)) && d
icon_state = "[word]"
Well look, if you wanna go optimization crazy then we can just use this:



mob
verb
textJoin()
for(var/x = 0, x < 100000, x++)
icon_state = "[locate(type) in get_step(src,NORTH) ? "N" : ""][locate(type) in get_step(src,SOUTH) ? "S" : ""][locate(type) in get_step(src,EAST) ? "E" : ""][locate(type) in get_step(src,WEST) ? "W" : ""]"
The reason I spaced mine out and use concatenation is so that it's easier for people to read but there's no real reason why functionally you can't just chuck the entire thing into a single line.
Yeah I didn't know how to turn yours into an inline. When I run it I'm getting mine running a little faster.

I'm not sure what you're saying about 30% difference.
Scrub it. When serialized, yours is faster... Oddly. (This definitely should not be the case)
In response to 8BitParagon
Oh yeah, I absolutely agree. I had a similar issue where I wrote what I thought was a mega efficient process then someone beat it using switch().

BYOND is really weird behind the scenes. There's so many thing that should be the fastest but just aren't.
Awesome. Will be using this!
Sadly it's 16-state joining only, but interesting nonetheless. I'm really curious why bitJoin() is slower though. I can see a few places to speed it up that I think would put it on top.

This is how I'd optimize bitJoin. First pass:
bitJoin()
for(var/x = 0, x < 100000, x++)
icon_state = ""
var/word = 0
for(var/d in cardinal_dirs)
// Don't do |= unless the if check passes
if(locate(type) in get_step(src,d)) word |= d
icon_state = "[word]"

Second pass:
bitJoin()
for(var/x = 0, x < 100000, x++)
icon_state = ""
var/word = 0
// unrolled loop; avoids loop overhead and var lookups
// hard-coded values are faster than consts
if(locate(type) in get_step(src,1)) word |= 1
if(locate(type) in get_step(src,2)) word |= 2
if(locate(type) in get_step(src,4)) word |= 4
if(locate(type) in get_step(src,8)) word |= 8
icon_state = "[word]"

Final pass:
bitJoin()
for(var/x = 0, x < 100000, x++)
icon_state = ""
var/word = 0
// + should be faster than | when they're guaranteed to be the same result
if(locate(type) in get_step(src,1)) word += 1
if(locate(type) in get_step(src,2)) word += 2
if(locate(type) in get_step(src,4)) word += 4
if(locate(type) in get_step(src,8)) word += 8
icon_state = "[word]"
In response to Lummox JR
Lummox JR wrote:
Sadly it's 16-state joining only, but interesting nonetheless.

Hey thanks for taking interest :)

As you probably already know you could easily make it 64 state if you wanted.

atom/proc/AutoJoin()

icon_state = ""

var/nextDir

nextDir = locate(type) in get_step(src,NORTH)
icon_state += nextDir ? "N" : ""
nextDir = locate(type) in get_step(src,SOUTH)
icon_state += nextDir ? "S" : ""
nextDir = locate(type) in get_step(src,EAST)
icon_state += nextDir ? "E" : ""
nextDir = locate(type) in get_step(src,WEST)
icon_state += nextDir ? "W" : ""

nextDir = locate(type) in get_step(src,NORTHEAST)
icon_state += nextDir ? "-NE" : ""
nextDir = locate(type) in get_step(src,NORTHWEST)
icon_state += nextDir ? "-NW" : ""
nextDir = locate(type) in get_step(src,SOUTHEAST)
icon_state += nextDir ? "-SE" : ""
nextDir = locate(type) in get_step(src,SOUTHWEST)
icon_state += nextDir ? "-SW" : ""

In response to Zecronious
That's actually 256-state. Although 256-state isn't actually useful for most projects; 47-state is way more common. To use that, though, you pretty much definitely want to use bit twiddling.
In response to Lummox JR
Haha woops yeah true. Power function.

47 states.. What's an example? O.o
47-state joining is basically your bog-standard autojoin. For example, say you want to connect a network of walls. These wall icons can be free-standing, ends, straight, corners, T-junctions, intersections, but that's only 16-state. 47-state allows you to have filled corners, so for instance a 2x2 block of walls can look like one big block.

I have a tutorial on all this called Dream Tutor: All Together Now. It explains the many kinds of 8-bit autojoining, including some esoteric forms.
In response to Lummox JR
Ah right. Cool, I actually remember reading that article a long time ago. Must have been about 4,5 years ago.
161-state joins are my favorite because they're so organic, but I've never put them into use in a real game. In my famous TurfLayers demo I used a modified concept for railings, though, and that's what inspired the new join types.
In response to Lummox JR
I prefer to make all my walls the same size as my icon_size and just save myself the hassle of doing so many states but I can appreciate looking at such a complex system.
There's an easier method, Foomerian joining, which only allows a single corner or edge. It's closer to the join types seen in old RPG games.
This is very nice. :)

++ Work, Zecronious.
In response to Kats
Thank you :)
Page: 1 2