The CSG Exporter needs my mesh generator to work as a tool in the editor. Gave it a try but still didn't end up working so I wrote a .obj exporter. It is indeed very simple, especially for my use case. A mesh has the surface_get_arrays() function which returned everything I needed. I think it would be nice if it said what order the items come in in that array of size 9.
After some printing, vertexes are i = 0, UVs are at i = 4, and vertex normals are at i = 1.
var arrs = mesh.surface_get_arrays(0)
var __my_file := File.new()
__my_file.open("res://terrain.obj", __my_file.WRITE)
assert(__my_file.is_open())
__my_file.store_line("# OBJ file")
for i in range(arrs[0].size()): # write vertex points
__my_file.store_line("v " + str(arrs[0][i].x) + " " + str(arrs[0][i].y) + " " + str(arrs[0][i].z))
for i in range(arrs[4].size()): # write UVs
__my_file.store_line("vt " + str(arrs[4][i].x) + " " + str(arrs[4][i].y))
for i in range(arrs[1].size()): # write vertex normals
__my_file.store_line("vn " + str(arrs[1][i].x) + " " + str(arrs[1][i].y) + " " + str(arrs[1][i].z))
__my_file.store_line("usemtl None\ns off")
var v = 0
while v < arrs[0].size():
var num1 = str(v + 1); var num2 = str(v + 2); var num3 = str(v + 3)
var text = "f " + num1 + "/" + num1 + "/" + num1 + " "
text += "" + num2 + "/" + num2 + "/" + num2 + " "
text += "" + num3 + "/" + num3 + "/" + num3 + ""
v += 3
__my_file.store_line(text)
__my_file.close()