Compare commits
2 Commits
1c165601c2
...
7facb3a9d1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7facb3a9d1 | ||
![]() |
aef3de3df9 |
393
gltf2tok3.py
Executable file
393
gltf2tok3.py
Executable file
@ -0,0 +1,393 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import pygltflib
|
||||||
|
import sys
|
||||||
|
import numpy
|
||||||
|
import os
|
||||||
|
import base64
|
||||||
|
import pathlib
|
||||||
|
import struct
|
||||||
|
|
||||||
|
def mat3_to_quat(m):
|
||||||
|
trace = numpy.trace(m)
|
||||||
|
|
||||||
|
if trace >= 0:
|
||||||
|
r = (1 + trace) ** 0.5
|
||||||
|
rinv = 0.5 / r
|
||||||
|
|
||||||
|
q0 = rinv * (m[1, 2] - m[2, 1])
|
||||||
|
q1 = rinv * (m[2, 0] - m[0, 2])
|
||||||
|
q2 = rinv * (m[0, 1] - m[1, 0])
|
||||||
|
q3 = r * 0.5
|
||||||
|
elif m[0, 0] >= m[1, 1] and m[0, 0] >= m[2, 2]:
|
||||||
|
r = (1 - m[1, 1] - m[2, 2] + m[0, 0]) ** 0.5
|
||||||
|
rinv = 0.5 / r
|
||||||
|
|
||||||
|
q0 = r * 0.5
|
||||||
|
q1 = rinv * (m[0, 1] + m[1, 0])
|
||||||
|
q2 = rinv * (m[0, 2] + m[2, 0])
|
||||||
|
q3 = rinv * (m[1, 2] - m[2, 1])
|
||||||
|
elif m[1, 1] >= m[2, 2]:
|
||||||
|
r = (1 - m[0, 0] - m[2, 2] + m[1, 1]) ** 0.5
|
||||||
|
rinv = 0.5 / r
|
||||||
|
|
||||||
|
q0 = rinv * (m[0, 1] + m[1, 0])
|
||||||
|
q1 = r * 0.5
|
||||||
|
q2 = rinv * (m[1, 2] + m[2, 1])
|
||||||
|
q3 = rinv * (m[2, 0] - m[0, 2])
|
||||||
|
else:
|
||||||
|
r = (1 - m[0, 0] - m[1, 1] + m[2, 2]) ** 0.5
|
||||||
|
rinv = 0.5 / r
|
||||||
|
|
||||||
|
q0 = rinv * (m[0, 2] + m[2, 0])
|
||||||
|
q1 = rinv * (m[1, 2] + m[2, 1])
|
||||||
|
q2 = r * 0.5
|
||||||
|
q3 = rinv * (m[0, 1] - m[1, 0])
|
||||||
|
|
||||||
|
q = numpy.array([q0, q1, q2, q3])
|
||||||
|
|
||||||
|
if q[3] < 0:
|
||||||
|
q = -q
|
||||||
|
|
||||||
|
return q
|
||||||
|
|
||||||
|
def mat3_from_quat(q):
|
||||||
|
b, c, d, a = q[0], q[1], q[2], q[3]
|
||||||
|
|
||||||
|
return numpy.array([
|
||||||
|
[a ** 2 + b ** 2 - c ** 2 - d ** 2, 2 * b * c + 2 * a * d, 2 * b * d - 2 * a * c],
|
||||||
|
[2 * b * c - 2 * a * d, a ** 2 - b ** 2 + c ** 2 - d ** 2, 2 * c * d - 2 * a * b],
|
||||||
|
[2 * b * d - 2 * a * c, 2 * c * d + 2 * a * b, a ** 2 - b ** 2 - c ** 2 + d ** 2],
|
||||||
|
])
|
||||||
|
|
||||||
|
def mat4_decompose(m):
|
||||||
|
translation = m[3][:3]
|
||||||
|
|
||||||
|
rs_matrix = m[:3, :3]
|
||||||
|
|
||||||
|
scale = (rs_matrix ** 2).sum(-1) ** 0.5
|
||||||
|
|
||||||
|
rs_matrix[0] /= scale[0]
|
||||||
|
rs_matrix[1] /= scale[1]
|
||||||
|
rs_matrix[2] /= scale[2]
|
||||||
|
|
||||||
|
if numpy.dot(numpy.cross(m[0][:3], m[1][:3]), m[2][:3]) < 0:
|
||||||
|
rs_matrix[0] *= -1
|
||||||
|
rs_matrix[1] *= -1
|
||||||
|
rs_matrix[2] *= -1
|
||||||
|
scale *= -1
|
||||||
|
|
||||||
|
return translation, mat3_to_quat(rs_matrix), scale
|
||||||
|
|
||||||
|
def mat4_compose(t, r, s):
|
||||||
|
m = numpy.zeros((4, 4))
|
||||||
|
|
||||||
|
rm = mat3_from_quat(r) if r is not None else numpy.eye(3)
|
||||||
|
|
||||||
|
if s is not None:
|
||||||
|
rm[0] *= s[0]
|
||||||
|
rm[1] *= s[1]
|
||||||
|
rm[2] *= s[2]
|
||||||
|
|
||||||
|
m[:3, :3] = rm
|
||||||
|
|
||||||
|
if t is not None:
|
||||||
|
m[3][:3] = t
|
||||||
|
|
||||||
|
m[3][3] = 1
|
||||||
|
|
||||||
|
return m
|
||||||
|
|
||||||
|
def lerp(a, b, alpha):
|
||||||
|
return a + (b - a) * alpha
|
||||||
|
|
||||||
|
def slerp(a, b, alpha):
|
||||||
|
angle = numpy.arccos(min(1, max(-1, numpy.dot(a, b))))
|
||||||
|
denominator = numpy.sin(angle)
|
||||||
|
if abs(denominator) < 0.000001:
|
||||||
|
return lerp(a, b, alpha)
|
||||||
|
return (a * numpy.sin((1 - alpha) * angle) + b * numpy.sin(alpha * angle)) / denominator
|
||||||
|
|
||||||
|
TYPE_SIZES = {
|
||||||
|
"SCALAR": 1,
|
||||||
|
"VEC2": 2,
|
||||||
|
"VEC3": 3,
|
||||||
|
"VEC4": 4,
|
||||||
|
"MAT2": 4,
|
||||||
|
"MAT4": 16,
|
||||||
|
"MAT3": 9,
|
||||||
|
pygltflib.FLOAT: 4,
|
||||||
|
pygltflib.UNSIGNED_INT: 4,
|
||||||
|
pygltflib.UNSIGNED_SHORT: 2,
|
||||||
|
pygltflib.UNSIGNED_BYTE: 1,
|
||||||
|
pygltflib.SHORT: 2,
|
||||||
|
pygltflib.BYTE: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTF_NUMPY_MAPPING = {
|
||||||
|
pygltflib.FLOAT: numpy.float32,
|
||||||
|
pygltflib.UNSIGNED_INT: numpy.uint32,
|
||||||
|
pygltflib.UNSIGNED_SHORT: numpy.uint16,
|
||||||
|
pygltflib.UNSIGNED_BYTE: numpy.uint8,
|
||||||
|
pygltflib.SHORT: numpy.int16,
|
||||||
|
pygltflib.BYTE: numpy.int8,
|
||||||
|
}
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
def err(s):
|
||||||
|
errors.append(s)
|
||||||
|
def err_barrier():
|
||||||
|
for e in errors:
|
||||||
|
print(e)
|
||||||
|
if os.name == "nt" and "PROMPT" not in os.environ:
|
||||||
|
raw_input()
|
||||||
|
if len(errors):
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
for input_filename in sys.argv[1:]:
|
||||||
|
gltf = pygltflib.GLTF2().load(input_filename)
|
||||||
|
gltf.convert_buffers(pygltflib.BufferFormat.DATAURI)
|
||||||
|
|
||||||
|
def get_nd(acc_idx):
|
||||||
|
if acc_idx == None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
accessor = gltf.accessors[acc_idx]
|
||||||
|
buf_view = gltf.bufferViews[accessor.bufferView]
|
||||||
|
buf = gltf.buffers[buf_view.buffer]
|
||||||
|
uri = buf.uri
|
||||||
|
|
||||||
|
if "base64," in uri:
|
||||||
|
buf_data = base64.decodebytes(buf.uri.split("base64,")[-1].encode())
|
||||||
|
else:
|
||||||
|
with open(uri, "rb") as urifile:
|
||||||
|
buf_data = urifile.read()
|
||||||
|
|
||||||
|
start = buf_view.byteOffset + accessor.byteOffset
|
||||||
|
array = numpy.frombuffer(buf_data[start : start + accessor.count * TYPE_SIZES[accessor.type] * TYPE_SIZES[accessor.componentType]], dtype = GLTF_NUMPY_MAPPING[accessor.componentType])
|
||||||
|
return numpy.reshape(array, (array.shape[0] // TYPE_SIZES[accessor.type], TYPE_SIZES[accessor.type]))
|
||||||
|
|
||||||
|
def get(acc_idx):
|
||||||
|
array = get_nd(acc_idx)
|
||||||
|
return array.ravel() if array is not None else None
|
||||||
|
|
||||||
|
mesh_nodes = [n for n in gltf.nodes if n.mesh != None]
|
||||||
|
|
||||||
|
if len(mesh_nodes) > 1:
|
||||||
|
err("All meshes except first are ignored")
|
||||||
|
|
||||||
|
mesh_node = mesh_nodes[0]
|
||||||
|
|
||||||
|
mesh = gltf.meshes[mesh_node.mesh]
|
||||||
|
skin = gltf.skins[mesh_node.skin] if mesh_node.skin != None else None
|
||||||
|
|
||||||
|
k3result = {
|
||||||
|
"animations": [],
|
||||||
|
"bones": [],
|
||||||
|
"meshes": [],
|
||||||
|
}
|
||||||
|
|
||||||
|
for primitive in mesh.primitives:
|
||||||
|
material_name = ""
|
||||||
|
|
||||||
|
if primitive.material is not None:
|
||||||
|
material_name = gltf.materials[primitive.material].name
|
||||||
|
if not material_name:
|
||||||
|
err("Missing material name")
|
||||||
|
material_name = ""
|
||||||
|
else:
|
||||||
|
err("Missing material information")
|
||||||
|
|
||||||
|
mehs = {
|
||||||
|
"positions": get_nd(primitive.attributes.POSITION),
|
||||||
|
"normals": get_nd(primitive.attributes.NORMAL),
|
||||||
|
"uvs": get_nd(primitive.attributes.TEXCOORD_0),
|
||||||
|
"colors": get_nd(primitive.attributes.COLOR_0),
|
||||||
|
"boneids": get_nd(primitive.attributes.JOINTS_0),
|
||||||
|
"boneweights": get_nd(primitive.attributes.WEIGHTS_0),
|
||||||
|
"indices": get(primitive.indices),
|
||||||
|
"material_name": material_name
|
||||||
|
}
|
||||||
|
|
||||||
|
if mehs["normals"] is None:
|
||||||
|
err("Missing normal data")
|
||||||
|
if mehs["uvs"] is None:
|
||||||
|
err("Missing UVs")
|
||||||
|
|
||||||
|
k3result["meshes"].append(mehs)
|
||||||
|
|
||||||
|
if len(skin.joints) > 255:
|
||||||
|
err("Bone maximum is 255")
|
||||||
|
|
||||||
|
err_barrier()
|
||||||
|
|
||||||
|
joint_gltf_to_k3_id_mapping = {}
|
||||||
|
joint_k3_to_gltf_id_mapping = {}
|
||||||
|
if skin:
|
||||||
|
# Topologically sort joints just in case they aren't
|
||||||
|
joint_parents = {i: next((j for j in skin.joints if i in gltf.nodes[j].children), None) for i in skin.joints}
|
||||||
|
joint_graph = joint_parents.copy()
|
||||||
|
while len(k3result["bones"]) != len(skin.joints):
|
||||||
|
minimal_elements = [k for k, v in joint_graph.items() if v == None]
|
||||||
|
for j in minimal_elements:
|
||||||
|
joint_gltf_to_k3_id_mapping[j] = len(k3result["bones"])
|
||||||
|
joint_k3_to_gltf_id_mapping[len(k3result["bones"])] = j
|
||||||
|
k3result["bones"].append({
|
||||||
|
"parent": joint_gltf_to_k3_id_mapping.get(joint_parents[j], 255),
|
||||||
|
"bind": mat4_compose(gltf.nodes[j].translation, gltf.nodes[j].rotation, gltf.nodes[j].scale)
|
||||||
|
})
|
||||||
|
for k, v in joint_graph.copy().items():
|
||||||
|
if v in minimal_elements:
|
||||||
|
joint_graph[k] = None
|
||||||
|
if v == None:
|
||||||
|
del joint_graph[k]
|
||||||
|
|
||||||
|
for k3b in k3result["bones"]:
|
||||||
|
if k3b["parent"] != 255:
|
||||||
|
k3b["bind"] = k3result["bones"][k3b["parent"]]["bind"] @ k3b["bind"]
|
||||||
|
|
||||||
|
for anim_idx, animation in enumerate(gltf.animations):
|
||||||
|
timelines = {}
|
||||||
|
duration = 0
|
||||||
|
|
||||||
|
# Fill timelines from GLTF data
|
||||||
|
|
||||||
|
for channel in animation.channels:
|
||||||
|
target_node = channel.target.node
|
||||||
|
|
||||||
|
if target_node not in joint_gltf_to_k3_id_mapping:
|
||||||
|
# Not a bone
|
||||||
|
continue
|
||||||
|
|
||||||
|
sampler = animation.samplers[channel.sampler]
|
||||||
|
times = get(sampler.input)
|
||||||
|
values = get_nd(sampler.output)
|
||||||
|
|
||||||
|
timeline = []
|
||||||
|
|
||||||
|
for t, v in zip(times, values):
|
||||||
|
timeline.append((t, v))
|
||||||
|
duration = max(duration, t)
|
||||||
|
|
||||||
|
timeline.sort(key = lambda kf: kf[0])
|
||||||
|
|
||||||
|
timelines.setdefault(joint_gltf_to_k3_id_mapping[target_node], {})[channel.target.path] = timeline
|
||||||
|
|
||||||
|
# Make sure that all bones & transform types have at least one keyframe
|
||||||
|
|
||||||
|
for bone_id, k3b in enumerate(k3result["bones"]):
|
||||||
|
bone_timelines = timelines.setdefault(bone_id, {})
|
||||||
|
l = bone_timelines.setdefault("translation", [])
|
||||||
|
if len(l) == 0:
|
||||||
|
l.append((0, numpy.array([0, 0, 0])))
|
||||||
|
l = bone_timelines.setdefault("rotation", [])
|
||||||
|
if len(l) == 0:
|
||||||
|
l.append((0, numpy.array([0, 0, 0, 1])))
|
||||||
|
l = bone_timelines.setdefault("scale", [])
|
||||||
|
if len(l) == 0:
|
||||||
|
l.append((0, numpy.array([1, 1, 1])))
|
||||||
|
|
||||||
|
# Playback and store all bone transforms per frame as k3 format needs
|
||||||
|
|
||||||
|
fps = 30
|
||||||
|
frame_interval = 1 / fps
|
||||||
|
|
||||||
|
frame_times = numpy.arange(0, duration, frame_interval)
|
||||||
|
|
||||||
|
k3anim = {"id": anim_idx, "fps": fps, "frames": []}
|
||||||
|
|
||||||
|
for t in frame_times:
|
||||||
|
bone_transfs = []
|
||||||
|
|
||||||
|
for bone_id, k3b in enumerate(k3result["bones"]):
|
||||||
|
def dothing(transf_type, interp_func):
|
||||||
|
tm = timelines[bone_id][transf_type]
|
||||||
|
k1 = [k for k in range(len(tm)) if tm[k][0] <= t]
|
||||||
|
k2 = [k for k in range(len(tm)) if tm[k][0] > t]
|
||||||
|
k1 = max(k1) if len(k1) else 0
|
||||||
|
k2 = min(k2) if len(k2) else len(tm) - 1
|
||||||
|
alpha = (t - tm[k1][0]) / (tm[k2][0] - tm[k1][0]) if tm[k2][0] != tm[k1][0] else 0
|
||||||
|
return interp_func(tm[k1][1], tm[k2][1], alpha)
|
||||||
|
translation = dothing("translation", lerp)
|
||||||
|
rotation = dothing("rotation", slerp)
|
||||||
|
scale = dothing("scale", lerp)
|
||||||
|
|
||||||
|
bone_transfs.append((translation, rotation))
|
||||||
|
|
||||||
|
k3anim["frames"].append(bone_transfs)
|
||||||
|
|
||||||
|
k3result["animations"].append(k3anim)
|
||||||
|
|
||||||
|
# Finally, output
|
||||||
|
|
||||||
|
output_filename = pathlib.Path(input_filename).with_suffix(".k3m")
|
||||||
|
|
||||||
|
with open(output_filename, "wb") as f:
|
||||||
|
f.write(b"K3M ")
|
||||||
|
|
||||||
|
vertex_count = sum([len(mesh["positions"]) for mesh in k3result["meshes"]])
|
||||||
|
index_count = sum([len(mesh["indices"]) for mesh in k3result["meshes"]])
|
||||||
|
|
||||||
|
f.write(struct.pack("I", vertex_count))
|
||||||
|
f.write(struct.pack("I", index_count))
|
||||||
|
f.write(struct.pack("B", len(k3result["bones"])))
|
||||||
|
|
||||||
|
colorsEnabled = any([mesh["colors"] is not None for mesh in k3result["meshes"]])
|
||||||
|
|
||||||
|
# todo
|
||||||
|
colorsEnabled = False
|
||||||
|
|
||||||
|
f.write(struct.pack("B", 1 if colorsEnabled else 0))
|
||||||
|
|
||||||
|
f.write(struct.pack("H", len(k3result["animations"])))
|
||||||
|
|
||||||
|
for k3b in k3result["bones"]:
|
||||||
|
f.write(struct.pack("16f", *numpy.reshape(numpy.linalg.inv(k3b["bind"]), (16,))))
|
||||||
|
for k3b in k3result["bones"]:
|
||||||
|
f.write(struct.pack("B", k3b["parent"]))
|
||||||
|
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
f.write(mesh["positions"][:, :3].astype(numpy.float32).ravel().tobytes())
|
||||||
|
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
normals = mesh["normals"][:, :3].astype(numpy.float32)
|
||||||
|
for i in range(len(normals)):
|
||||||
|
normals[i] /= numpy.max(numpy.abs(normals[i]))
|
||||||
|
normals[i] *= 127
|
||||||
|
f.write(normals.astype(numpy.int8).ravel().tobytes())
|
||||||
|
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
f.write(mesh["uvs"][:, :2].astype(numpy.float32).ravel().tobytes())
|
||||||
|
|
||||||
|
if mesh["boneids"] is not None:
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
f.write(mesh["boneids"][:, :4].astype(numpy.int8).ravel().tobytes())
|
||||||
|
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
f.write((mesh["boneweights"][:, :4].astype(numpy.float32) * 65535).astype(numpy.int16).ravel().tobytes())
|
||||||
|
|
||||||
|
if colorsEnabled:
|
||||||
|
# TODO
|
||||||
|
#for mesh in k3result["colors"]:
|
||||||
|
# f.write(mesh["colors"][:, :4])
|
||||||
|
pass
|
||||||
|
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
f.write(mesh["indices"].astype(numpy.uint16).tobytes())
|
||||||
|
|
||||||
|
f.write(struct.pack("H", len(k3result["meshes"])))
|
||||||
|
|
||||||
|
offset = 0
|
||||||
|
for mesh in k3result["meshes"]:
|
||||||
|
ind_count = len(mesh["indices"])
|
||||||
|
f.write(struct.pack("2H", offset, ind_count))
|
||||||
|
f.write(mesh["material_name"].encode("UTF-8") + b'\x00')
|
||||||
|
offset += ind_count
|
||||||
|
|
||||||
|
for anim in k3result["animations"]:
|
||||||
|
f.write(struct.pack("4H", anim["id"], len(anim["frames"]), anim["fps"], 0))
|
||||||
|
|
||||||
|
for frame in anim["frames"]:
|
||||||
|
for bone_idx in range(len(k3result["bones"])):
|
||||||
|
f.write(struct.pack("4f", frame[bone_idx][0][0], frame[bone_idx][0][1], frame[bone_idx][0][2], 1))
|
||||||
|
f.write(struct.pack("4f", *frame[bone_idx][1]))
|
14
src/k4.h
14
src/k4.h
@ -5,20 +5,26 @@
|
|||||||
struct k3MScreen;
|
struct k3MScreen;
|
||||||
|
|
||||||
#include"stoon.h"
|
#include"stoon.h"
|
||||||
struct NetWrap {
|
/*struct NetWrap {
|
||||||
struct Stoon stoon;
|
struct Stoon stoon;
|
||||||
|
|
||||||
int stage;
|
int stage;
|
||||||
float timeout;
|
float timeout;
|
||||||
|
|
||||||
int isHost;
|
bool isHost;
|
||||||
|
|
||||||
// Used for punching stage
|
// Used for punching stage
|
||||||
int gotten;
|
int gotten;
|
||||||
|
|
||||||
char otherpeer[STOON_CONN_INFO_SIZE];
|
// Server-side
|
||||||
|
#define NETWRAP_BACKLOG 32
|
||||||
|
char otherpeers[NETWRAP_BACKLOG][STOON_CONN_INFO_SIZE];
|
||||||
|
bool otherpeersActive[NETWRAP_BACKLOG];
|
||||||
|
|
||||||
|
// Client-side
|
||||||
|
char connectto[STOON_CONN_INFO_SIZE];
|
||||||
};
|
};
|
||||||
extern struct NetWrap NetWrap;
|
extern struct NetWrap NetWrap;*/
|
||||||
|
|
||||||
extern struct k3MScreen *UiActive;
|
extern struct k3MScreen *UiActive;
|
||||||
|
|
||||||
|
153
src/luaapi.c
153
src/luaapi.c
@ -14,6 +14,7 @@
|
|||||||
#include"net.h"
|
#include"net.h"
|
||||||
#include"k3menu.h"
|
#include"k3menu.h"
|
||||||
#include<assert.h>
|
#include<assert.h>
|
||||||
|
#include"net_hi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is by far the least clean or well-maintained source in the
|
* This is by far the least clean or well-maintained source in the
|
||||||
@ -2131,18 +2132,42 @@ static int dagame_set_texture_reduction(lua_State *L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int PeercodeHandler = LUA_NOREF;
|
int PeercodeHandler = LUA_NOREF;
|
||||||
static int dagame_net_gen_peercode(lua_State *L) {
|
static void get_peercode_callback(void *ud, const char *peercode_bin) {
|
||||||
if(NetWrap.stage != 0 || PeercodeHandler != LUA_NOREF) {
|
char peercode[STOON_CONN_INFO_SIZE * 2 + 1] = {};
|
||||||
lua_pushliteral(L, "Peercode generation already in progress");
|
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
|
||||||
lua_error(L);
|
snprintf(peercode + i * 2, 3, "%02x", ((uint8_t*) peercode_bin)[i]);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
|
if(PeercodeHandler == LUA_NOREF) {
|
||||||
NetWrap.stage = 1;
|
puts("Peercode found but no handler");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
lua_pushvalue(L, 1);
|
lua_rawgeti(L, LUA_REGISTRYINDEX, PeercodeHandler);
|
||||||
PeercodeHandler = luaL_ref(L, LUA_REGISTRYINDEX);
|
if(lua_isnil(L, -1)) {
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
lua_pushstring(L, peercode);
|
||||||
|
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
||||||
|
puts(lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
|
||||||
|
luaL_unref(L, LUA_REGISTRYINDEX, PeercodeHandler);
|
||||||
|
PeercodeHandler = LUA_NOREF;
|
||||||
|
}
|
||||||
|
static int dagame_net_gen_peercode(lua_State *L) {
|
||||||
|
if(net_hi_request_peercode(NULL, get_peercode_callback)) {
|
||||||
|
lua_pushvalue(L, 1);
|
||||||
|
PeercodeHandler = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||||
|
} else {
|
||||||
|
lua_pushliteral(L, "Cannot request peercode");
|
||||||
|
lua_error(L);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2175,8 +2200,14 @@ static int dagame_clipboard_get(lua_State *L) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CONN_INVALID_PEERCODE 1
|
static int get_peercode_bin(const char *peercode, char *peercode_bin) {
|
||||||
static int conn(const char *peercode, bool host) {
|
if(!peercode) return 0;
|
||||||
|
if(!peercode_bin) return 0;
|
||||||
|
|
||||||
|
if(strlen(peercode) < 2 * STOON_CONN_INFO_SIZE) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
|
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
|
||||||
int b = 0;
|
int b = 0;
|
||||||
|
|
||||||
@ -2184,55 +2215,52 @@ static int conn(const char *peercode, bool host) {
|
|||||||
b |= (peercode[i * 2 + 0] - '0') << 4;
|
b |= (peercode[i * 2 + 0] - '0') << 4;
|
||||||
} else if(peercode[i * 2 + 0] >= 'a' && peercode[i * 2 + 0] <= 'f') {
|
} else if(peercode[i * 2 + 0] >= 'a' && peercode[i * 2 + 0] <= 'f') {
|
||||||
b |= (peercode[i * 2 + 0] - 'a' + 10) << 4;
|
b |= (peercode[i * 2 + 0] - 'a' + 10) << 4;
|
||||||
} else return CONN_INVALID_PEERCODE;
|
} else return 0;
|
||||||
|
|
||||||
if(peercode[i * 2 + 1] >= '0' && peercode[i * 2 + 1] <= '9') {
|
if(peercode[i * 2 + 1] >= '0' && peercode[i * 2 + 1] <= '9') {
|
||||||
b |= (peercode[i * 2 + 1] - '0') << 0;
|
b |= (peercode[i * 2 + 1] - '0') << 0;
|
||||||
} else if(peercode[i * 2 + 1] >= 'a' && peercode[i * 2 + 1] <= 'f') {
|
} else if(peercode[i * 2 + 1] >= 'a' && peercode[i * 2 + 1] <= 'f') {
|
||||||
b |= (peercode[i * 2 + 1] - 'a' + 10) << 0;
|
b |= (peercode[i * 2 + 1] - 'a' + 10) << 0;
|
||||||
} else return CONN_INVALID_PEERCODE;
|
} else return 0;
|
||||||
|
|
||||||
NetWrap.otherpeer[i] = b;
|
peercode_bin[i] = b;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetWrap.isHost = host;
|
return 1;
|
||||||
NetWrap.stage = 3;
|
}
|
||||||
|
|
||||||
|
static int dagame_net_host(lua_State *L) {
|
||||||
|
lua_pushboolean(L, net_hi_setup(true));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dagame_net_host(lua_State *L) {
|
static int dagame_net_join(lua_State *L) {
|
||||||
int status = conn(lua_tostring(L, 1), true);
|
char peercode[STOON_CONN_INFO_SIZE];
|
||||||
|
if(!get_peercode_bin(lua_tostring(L, 1), peercode)) {
|
||||||
lua_pushboolean(L, !status);
|
lua_pushliteral(L, "Invalid peercode");
|
||||||
|
lua_error(L);
|
||||||
if(status) {
|
return 0;
|
||||||
if(status == CONN_INVALID_PEERCODE) {
|
|
||||||
lua_pushliteral(L, "peercode");
|
|
||||||
} else {
|
|
||||||
lua_pushliteral(L, "unknown");
|
|
||||||
}
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
net_hi_setup(false);
|
||||||
|
|
||||||
|
lua_pushboolean(L, net_hi_connect(peercode));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dagame_net_join(lua_State *L) {
|
static int dagame_net_punch(lua_State *L) {
|
||||||
int status = conn(lua_tostring(L, 1), false);
|
char peercode[STOON_CONN_INFO_SIZE];
|
||||||
|
if(!get_peercode_bin(lua_tostring(L, 1), peercode)) {
|
||||||
lua_pushboolean(L, !status);
|
lua_pushliteral(L, "Invalid peercode");
|
||||||
|
lua_error(L);
|
||||||
if(status) {
|
return 0;
|
||||||
if(status == CONN_INVALID_PEERCODE) {
|
|
||||||
lua_pushliteral(L, "peercode");
|
|
||||||
} else {
|
|
||||||
lua_pushliteral(L, "unknown");
|
|
||||||
}
|
|
||||||
return 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
net_hi_add_punch(peercode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include<GLFW/glfw3.h>
|
#include<GLFW/glfw3.h>
|
||||||
@ -2403,6 +2431,9 @@ void luaapi_init() {
|
|||||||
lua_pushcfunction(L, dagame_net_host);
|
lua_pushcfunction(L, dagame_net_host);
|
||||||
lua_setfield(L, -2, "host");
|
lua_setfield(L, -2, "host");
|
||||||
|
|
||||||
|
lua_pushcfunction(L, dagame_net_punch);
|
||||||
|
lua_setfield(L, -2, "punch");
|
||||||
|
|
||||||
lua_pushcfunction(L, dagame_net_join);
|
lua_pushcfunction(L, dagame_net_join);
|
||||||
lua_setfield(L, -2, "join");
|
lua_setfield(L, -2, "join");
|
||||||
lua_setfield(L, -2, "net");
|
lua_setfield(L, -2, "net");
|
||||||
@ -3337,22 +3368,6 @@ void luaapi_cleanup() {
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*void luaapi_perform(const char *statement) {
|
|
||||||
puts(statement);
|
|
||||||
if(luaL_loadstring(L, statement) != LUA_OK) {
|
|
||||||
puts(lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, consoleEnvironment);
|
|
||||||
lua_setupvalue(L, -2, 1);
|
|
||||||
if(lua_pcall(L, 0, 0, 0) != LUA_OK) {
|
|
||||||
puts(lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
void luaapi_ctrlev(int ctrl, int action) {
|
void luaapi_ctrlev(int ctrl, int action) {
|
||||||
lua_getglobal(L, "game");
|
lua_getglobal(L, "game");
|
||||||
lua_getfield(L, -1, "ctrl");
|
lua_getfield(L, -1, "ctrl");
|
||||||
@ -3430,30 +3445,6 @@ void luaapi_escape() {
|
|||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void luaapi_peercode_found(const char *peercode) {
|
|
||||||
if(PeercodeHandler == LUA_NOREF) {
|
|
||||||
puts("Peercode found but no handler");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_rawgeti(L, LUA_REGISTRYINDEX, PeercodeHandler);
|
|
||||||
if(lua_isnil(L, -1)) {
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
lua_pushstring(L, peercode);
|
|
||||||
if(lua_pcall(L, 1, 0, 0) != LUA_OK) {
|
|
||||||
puts(lua_tostring(L, -1));
|
|
||||||
lua_pop(L, 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lua_pop(L, 1);
|
|
||||||
|
|
||||||
luaL_unref(L, LUA_REGISTRYINDEX, PeercodeHandler);
|
|
||||||
PeercodeHandler = LUA_NOREF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void luaapi_update() {
|
void luaapi_update() {
|
||||||
lua_getglobal(L, "game");
|
lua_getglobal(L, "game");
|
||||||
lua_getfield(L, -1, "update");
|
lua_getfield(L, -1, "update");
|
||||||
|
229
src/main.c
229
src/main.c
@ -40,8 +40,6 @@
|
|||||||
|
|
||||||
#include<ctype.h>
|
#include<ctype.h>
|
||||||
|
|
||||||
struct NetWrap NetWrap;
|
|
||||||
|
|
||||||
GLFWwindow *GameWnd;
|
GLFWwindow *GameWnd;
|
||||||
|
|
||||||
static int TextureResolutionReduction = 0;
|
static int TextureResolutionReduction = 0;
|
||||||
@ -186,7 +184,7 @@ const char *k4_get_arg(const char *name) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netwrap_step() {
|
/*static void netwrap_step() {
|
||||||
if(NetWrap.stage && CurrentTime >= NetWrap.timeout) {
|
if(NetWrap.stage && CurrentTime >= NetWrap.timeout) {
|
||||||
if(NetWrap.stage == 1) {
|
if(NetWrap.stage == 1) {
|
||||||
if(stoon_req(&NetWrap.stoon)) {
|
if(stoon_req(&NetWrap.stoon)) {
|
||||||
@ -201,11 +199,6 @@ static void netwrap_step() {
|
|||||||
|
|
||||||
luaapi_peercode_found(str);
|
luaapi_peercode_found(str);
|
||||||
|
|
||||||
//glfwSetClipboardString(NULL, str);
|
|
||||||
|
|
||||||
//screenMain.lblpeerdata->invisible = 0;
|
|
||||||
//screenMain.btnconnect->invisible = 0;
|
|
||||||
|
|
||||||
NetWrap.stage = 2;
|
NetWrap.stage = 2;
|
||||||
} else {
|
} else {
|
||||||
k3Log(k3_INFO, "Stoon listen timeout.");
|
k3Log(k3_INFO, "Stoon listen timeout.");
|
||||||
@ -217,51 +210,59 @@ static void netwrap_step() {
|
|||||||
}
|
}
|
||||||
} else if(NetWrap.stage == 2) {
|
} else if(NetWrap.stage == 2) {
|
||||||
stoon_keepalive(&NetWrap.stoon);
|
stoon_keepalive(&NetWrap.stoon);
|
||||||
|
|
||||||
NetWrap.timeout = CurrentTime + 1;
|
NetWrap.timeout = CurrentTime + 1;
|
||||||
} else if(NetWrap.stage == 3) {
|
} else if(NetWrap.stage == 3) {
|
||||||
int status = stoon_poonch(&NetWrap.stoon, NetWrap.otherpeer);
|
if(NetWrap.isHost) {
|
||||||
|
|
||||||
//screenMain.lblpeerdata->txt = strdup("Trying to connect...\nMay not work if both are\nbehind symmetric NATs.");
|
|
||||||
|
|
||||||
if(status == STOON_POONCH_INCOMPATIBLE_NETFAMS) {
|
|
||||||
NetWrap.stage = 0;
|
|
||||||
|
|
||||||
stoon_kill(&NetWrap.stoon);
|
stoon_kill(&NetWrap.stoon);
|
||||||
|
net_server_init();
|
||||||
|
NetWrap.stage = 4;
|
||||||
|
}
|
||||||
|
} else if(NetWrap.stage == 4) {
|
||||||
|
if(NetWrap.isHost) {
|
||||||
|
ENetBuffer buf = {.data = "Punch!", .dataLength = 6};
|
||||||
|
|
||||||
//screenMain.lblpeerdata->txt = strdup("Connection cannot be established:\nIncompatible netfams.");
|
ENetHost *h = net_server_get_enethost();
|
||||||
} else if(status == STOON_POONCH_NO_KNOCK && NetWrap.stoon.poonchstage == POONCH_STAGE_ACK) {
|
|
||||||
if(NetWrap.gotten++ > 5) {
|
|
||||||
NetWrap.stage = 0;
|
|
||||||
stoon_kill(&NetWrap.stoon);
|
|
||||||
|
|
||||||
if(NetWrap.isHost) {
|
for(size_t i = 0; i < NETWRAP_BACKLOG; i++) {
|
||||||
net_server_init();
|
if(NetWrap.otherpeersActive[i]) {
|
||||||
} else {
|
ENetAddress v4 = {}, v6 = {};
|
||||||
char ip[64];
|
stoonpeer_to_enets(NetWrap.otherpeers[i], &v4, &v6);
|
||||||
int port;
|
|
||||||
if(*(uint16_t*) (NetWrap.otherpeer + 22) == 0) {
|
|
||||||
inet_ntop(AF_INET, NetWrap.otherpeer, ip, sizeof(ip));
|
|
||||||
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 4));
|
|
||||||
} else {
|
|
||||||
inet_ntop(AF_INET6, NetWrap.otherpeer + 6, ip, sizeof(ip));
|
|
||||||
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 22));
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("Trying [%s]:%u\n", ip, port);
|
enet_socket_send(h->socket, &v4, &buf, 1);
|
||||||
|
enet_socket_send(h->socket, &v6, &buf, 1);
|
||||||
net_client_init();
|
|
||||||
net_client_connect(ip, port);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//screenMain.lblpeerdata->txt = strdup("Connection successful.");
|
|
||||||
}
|
}
|
||||||
} else NetWrap.gotten = 0;
|
} else {
|
||||||
|
stoon_keepalive(&NetWrap.stoon);
|
||||||
|
}
|
||||||
|
|
||||||
|
NetWrap.timeout = CurrentTime + 1;
|
||||||
|
} else if(NetWrap.stage == 5) {
|
||||||
|
if(!NetWrap.isHost) {
|
||||||
|
char ip[64];
|
||||||
|
int port;
|
||||||
|
if(*(uint16_t*) (NetWrap.otherpeer + 22) == 0) {
|
||||||
|
inet_ntop(AF_INET, NetWrap.otherpeer, ip, sizeof(ip));
|
||||||
|
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 4));
|
||||||
|
} else {
|
||||||
|
inet_ntop(AF_INET6, NetWrap.otherpeer + 6, ip, sizeof(ip));
|
||||||
|
port = ntohs(*(uint16_t*) (NetWrap.otherpeer + 22));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Trying [%s]:%u\n", ip, port);
|
||||||
|
|
||||||
|
net_client_init();
|
||||||
|
if(net_client_connect(ip, port)) {
|
||||||
|
NetWrap.stage = 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetWrap.timeout = CurrentTime + 0.5;
|
||||||
|
} else {
|
||||||
NetWrap.timeout = CurrentTime + 1;
|
NetWrap.timeout = CurrentTime + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
#include<signal.h>
|
#include<signal.h>
|
||||||
void k4k3LogCallback(enum k3LogLevel lvl, const char *str, size_t len) {
|
void k4k3LogCallback(enum k3LogLevel lvl, const char *str, size_t len) {
|
||||||
@ -373,150 +374,6 @@ static void fix_resol() {
|
|||||||
gr_lowres(roundf(w * ResolPercentage / 100.f / 4) * 4, roundf(h * ResolPercentage / 100.f / 4) * 4);
|
gr_lowres(roundf(w * ResolPercentage / 100.f / 4) * 4, roundf(h * ResolPercentage / 100.f / 4) * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool onqualitypress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
k3GraphicalReduction = (k3GraphicalReduction + 1) % 3;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool onresolpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
struct k3MTextButton *btn = (void*) ev->target;
|
|
||||||
|
|
||||||
ResolPercentage -= 10;
|
|
||||||
|
|
||||||
if(ResolPercentage <= 0) {
|
|
||||||
ResolPercentage = 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *txt = NULL;
|
|
||||||
|
|
||||||
switch(ResolPercentage) {
|
|
||||||
case 10:
|
|
||||||
txt = "10%";
|
|
||||||
break;
|
|
||||||
case 20:
|
|
||||||
txt = "20%";
|
|
||||||
break;
|
|
||||||
case 30:
|
|
||||||
txt = "30%";
|
|
||||||
break;
|
|
||||||
case 40:
|
|
||||||
txt = "40%";
|
|
||||||
break;
|
|
||||||
case 50:
|
|
||||||
txt = "50%";
|
|
||||||
break;
|
|
||||||
case 60:
|
|
||||||
txt = "60%";
|
|
||||||
break;
|
|
||||||
case 70:
|
|
||||||
txt = "70%";
|
|
||||||
break;
|
|
||||||
case 80:
|
|
||||||
txt = "80%";
|
|
||||||
break;
|
|
||||||
case 90:
|
|
||||||
txt = "90%";
|
|
||||||
break;
|
|
||||||
case 100:
|
|
||||||
txt = "Full Resolution";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
btn->txt = strdup(txt);
|
|
||||||
|
|
||||||
fix_resol();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool ontexrespress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
TextureResolutionReduction = (TextureResolutionReduction + 1) % 3;
|
|
||||||
refresh_textures();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool onresumepress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
UiActive = NULL;
|
|
||||||
set_ui_mode(0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#ifdef LOCALHOST_ONLY
|
|
||||||
static bool onhostpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
net_server_init();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool onjoinpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
net_client_init();
|
|
||||||
net_client_connect("127.0.0.1", 26656);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool onconnectpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static bool onhostpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
screenMain.btnhost->disabled = 1;
|
|
||||||
screenMain.btnjoin->disabled = 1;
|
|
||||||
|
|
||||||
NetWrap.stage = 1;
|
|
||||||
NetWrap.timeout = glfwGetTime() + 0;
|
|
||||||
NetWrap.isHost = 1;
|
|
||||||
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool onjoinpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
screenMain.btnhost->disabled = 1;
|
|
||||||
screenMain.btnjoin->disabled = 1;
|
|
||||||
|
|
||||||
NetWrap.stage = 1;
|
|
||||||
NetWrap.timeout = glfwGetTime() + 0;
|
|
||||||
NetWrap.isHost = 0;
|
|
||||||
NetWrap.stoon = stoon_init("stun.easybell.de", 3478, 26656);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
static bool onconnectpress(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
const char *name = glfwGetClipboardString(NULL);
|
|
||||||
|
|
||||||
while(isspace(*name)) name++;
|
|
||||||
|
|
||||||
if(strlen(name) < STOON_CONN_INFO_SIZE * 2) {
|
|
||||||
goto bad;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < STOON_CONN_INFO_SIZE; i++) {
|
|
||||||
int b = 0;
|
|
||||||
|
|
||||||
if(name[i * 2 + 0] >= '0' && name[i * 2 + 0] <= '9') {
|
|
||||||
b |= (name[i * 2 + 0] - '0') << 4;
|
|
||||||
} else if(name[i * 2 + 0] >= 'a' && name[i * 2 + 0] <= 'f') {
|
|
||||||
b |= (name[i * 2 + 0] - 'a' + 10) << 4;
|
|
||||||
} else goto bad;
|
|
||||||
|
|
||||||
if(name[i * 2 + 1] >= '0' && name[i * 2 + 1] <= '9') {
|
|
||||||
b |= (name[i * 2 + 1] - '0') << 0;
|
|
||||||
} else if(name[i * 2 + 1] >= 'a' && name[i * 2 + 1] <= 'f') {
|
|
||||||
b |= (name[i * 2 + 1] - 'a' + 10) << 0;
|
|
||||||
} else goto bad;
|
|
||||||
|
|
||||||
NetWrap.otherpeer[i] = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
NetWrap.stage = 3;
|
|
||||||
screenMain.btnconnect->disabled = 1;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
bad:
|
|
||||||
screenMain.lblpeerdata->txt = strdup("Incorrect peer conndata.");
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
static bool onconsoleenter(struct k3MEvent *ev, uint8_t *ud) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void eng_ui_init() {
|
static void eng_ui_init() {
|
||||||
set_ui_mode(1);
|
set_ui_mode(1);
|
||||||
}
|
}
|
||||||
@ -663,7 +520,7 @@ int main(int argc_, char **argv_) {
|
|||||||
|
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
netwrap_step();
|
net_hi_update(CurrentTime);
|
||||||
|
|
||||||
float alpha = fmodf(accumulator * GAME_TPS, 1.f);
|
float alpha = fmodf(accumulator * GAME_TPS, 1.f);
|
||||||
|
|
||||||
|
@ -26,12 +26,20 @@ void net_client_init() {
|
|||||||
Game.isAuthority = 0;
|
Game.isAuthority = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void net_client_connect(const char *addr, uint16_t port) {
|
bool net_client_connect(const char *addr, uint16_t port) {
|
||||||
ENetAddress eaddr;
|
ENetAddress eaddr;
|
||||||
enet_address_set_host(&eaddr, addr);
|
enet_address_set_host(&eaddr, addr);
|
||||||
eaddr.port = port;
|
eaddr.port = port;
|
||||||
|
|
||||||
peer = enet_host_connect(host, &eaddr, 1, 0);
|
peer = enet_host_connect(host, &eaddr, 1, 0);
|
||||||
|
|
||||||
|
ENetEvent ev;
|
||||||
|
if(enet_host_service(host, &ev, 200) <= 0 || ev.type != ENET_EVENT_TYPE_CONNECT) {
|
||||||
|
enet_peer_reset(peer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern double glfwGetTime();
|
extern double glfwGetTime();
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
void net_client_init();
|
void net_client_init();
|
||||||
void net_client_connect(const char *addr, uint16_t port);
|
bool net_client_connect(const char *addr, uint16_t port);
|
||||||
void net_client_receive();
|
void net_client_receive();
|
||||||
void net_client_update();
|
void net_client_update();
|
||||||
void net_client_dejitter();
|
void net_client_dejitter();
|
||||||
|
165
src/net_hi.c
Normal file
165
src/net_hi.c
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#include"net_hi.h"
|
||||||
|
|
||||||
|
#include<stddef.h>
|
||||||
|
#include"enet.h"
|
||||||
|
#include<stdlib.h>
|
||||||
|
#include"stoon.h"
|
||||||
|
#include"net_server.h"
|
||||||
|
#include"net_client.h"
|
||||||
|
#include<math.h>
|
||||||
|
|
||||||
|
static void *ReqPeercodeUD;
|
||||||
|
static void(*ReqPeercodeCB)(void*, const char *peercode);
|
||||||
|
|
||||||
|
static struct Stoon stoon;
|
||||||
|
|
||||||
|
static bool inited = false;
|
||||||
|
static bool isHost;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
#define MASK_IPv4 1
|
||||||
|
#define MASK_IPv6 2
|
||||||
|
int mask;
|
||||||
|
ENetAddress v4;
|
||||||
|
ENetAddress v6;
|
||||||
|
} ToPunch;
|
||||||
|
static ToPunch *topunch = NULL;
|
||||||
|
static size_t topunchCount = 0;
|
||||||
|
|
||||||
|
static double Timeout = 0;
|
||||||
|
|
||||||
|
static bool connected = false;
|
||||||
|
|
||||||
|
bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode)) {
|
||||||
|
if(inited) return false;
|
||||||
|
|
||||||
|
ReqPeercodeUD = ud;
|
||||||
|
ReqPeercodeCB = callback;
|
||||||
|
|
||||||
|
stoon = stoon_init("stun.easybell.de", 3478, 26656);
|
||||||
|
|
||||||
|
Timeout = 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool net_hi_setup(bool host) {
|
||||||
|
if(inited) return false;
|
||||||
|
|
||||||
|
stoon_kill(&stoon);
|
||||||
|
|
||||||
|
inited = true;
|
||||||
|
isHost = host;
|
||||||
|
|
||||||
|
if(host) {
|
||||||
|
net_server_init();
|
||||||
|
} else {
|
||||||
|
net_client_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void net_hi_update(double now) {
|
||||||
|
if(now <= Timeout) return;
|
||||||
|
|
||||||
|
if(ReqPeercodeCB) {
|
||||||
|
|
||||||
|
if(stoon_req(&stoon)) {
|
||||||
|
if(stoon_listen(&stoon)) {
|
||||||
|
uint8_t peercode[STOON_CONN_INFO_SIZE] = {};
|
||||||
|
stoon_serialize(&stoon, peercode);
|
||||||
|
|
||||||
|
ReqPeercodeCB(ReqPeercodeUD, peercode);
|
||||||
|
|
||||||
|
ReqPeercodeCB = NULL;
|
||||||
|
} else {
|
||||||
|
Timeout = now + 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Timeout = now + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if(!inited) {
|
||||||
|
|
||||||
|
stoon_keepalive(&stoon);
|
||||||
|
|
||||||
|
Timeout = now + 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(isHost) {
|
||||||
|
|
||||||
|
ENetHost *h = net_server_get_enethost();
|
||||||
|
|
||||||
|
ENetBuffer buf = {.data = "Punch!", .dataLength = 6};
|
||||||
|
|
||||||
|
for(size_t tpi = 0; tpi < topunchCount; tpi++) {
|
||||||
|
ToPunch *tp = &topunch[tpi];
|
||||||
|
|
||||||
|
if(tp->mask & MASK_IPv4) {
|
||||||
|
enet_socket_send(h->socket, &tp->v4, &buf, 1);
|
||||||
|
} else if(tp->mask & MASK_IPv6) {
|
||||||
|
enet_socket_send(h->socket, &tp->v6, &buf, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Timeout = now + 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void stoonpeer_to_enets(const char *peercode, ENetAddress *v4, ENetAddress *v6, int *mask) {
|
||||||
|
memset(v4->host.__in6_u.__u6_addr8, 0, 16);
|
||||||
|
v4->host.__in6_u.__u6_addr8[10] = 0xFF;
|
||||||
|
v4->host.__in6_u.__u6_addr8[11] = 0xFF;
|
||||||
|
v4->host.__in6_u.__u6_addr8[12] = peercode[0];
|
||||||
|
v4->host.__in6_u.__u6_addr8[13] = peercode[1];
|
||||||
|
v4->host.__in6_u.__u6_addr8[14] = peercode[2];
|
||||||
|
v4->host.__in6_u.__u6_addr8[15] = peercode[3];
|
||||||
|
v4->port = ntohs(*(uint16_t*) &peercode[4]);
|
||||||
|
|
||||||
|
memcpy(v6->host.__in6_u.__u6_addr8, peercode + 6, 16);
|
||||||
|
v6->port = ntohs(*(uint16_t*) &peercode[22]);
|
||||||
|
|
||||||
|
*mask = 0;
|
||||||
|
if(v4->port) {
|
||||||
|
*mask |= MASK_IPv4;
|
||||||
|
}
|
||||||
|
if(v6->port) {
|
||||||
|
*mask |= MASK_IPv6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void net_hi_add_punch(const char *peercode) {
|
||||||
|
int mask;
|
||||||
|
ENetAddress v4 = {}, v6 = {};
|
||||||
|
stoonpeer_to_enets(peercode, &v4, &v6, &mask);
|
||||||
|
|
||||||
|
topunch = realloc(topunch, sizeof(*topunch) * (++topunchCount));
|
||||||
|
topunch[topunchCount - 1] = (ToPunch) {
|
||||||
|
.v4 = v4,
|
||||||
|
.v6 = v6,
|
||||||
|
.mask = mask,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool net_hi_connect(const char *peercode) {
|
||||||
|
if(!inited) return false;
|
||||||
|
|
||||||
|
if(connected) return false;
|
||||||
|
|
||||||
|
char ip[64];
|
||||||
|
int port;
|
||||||
|
if(*(uint16_t*) (peercode + 22) == 0) {
|
||||||
|
inet_ntop(AF_INET, peercode, ip, sizeof(ip));
|
||||||
|
port = ntohs(*(uint16_t*) (peercode + 4));
|
||||||
|
} else {
|
||||||
|
inet_ntop(AF_INET6, peercode + 6, ip, sizeof(ip));
|
||||||
|
port = ntohs(*(uint16_t*) (peercode + 22));
|
||||||
|
}
|
||||||
|
|
||||||
|
return net_client_connect(ip, port);
|
||||||
|
}
|
11
src/net_hi.h
Normal file
11
src/net_hi.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include<stdbool.h>
|
||||||
|
|
||||||
|
bool net_hi_request_peercode(void *ud, void(*callback)(void*, const char *peercode));
|
||||||
|
bool net_hi_setup(bool host);
|
||||||
|
void net_hi_update(double now);
|
||||||
|
|
||||||
|
void net_hi_add_punch(const char *peercode);
|
||||||
|
|
||||||
|
bool net_hi_connect(const char *peercode);
|
@ -342,3 +342,7 @@ void net_server_broadcast_msg(struct bstr *data) {
|
|||||||
|
|
||||||
free(b.data);
|
free(b.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *net_server_get_enethost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
@ -14,3 +14,5 @@ void net_server_force_load(struct _ENetPeer *peer, const char *script);
|
|||||||
|
|
||||||
void net_server_send_msg(struct _ENetPeer *peer, struct bstr *data);
|
void net_server_send_msg(struct _ENetPeer *peer, struct bstr *data);
|
||||||
void net_server_broadcast_msg(struct bstr *data);
|
void net_server_broadcast_msg(struct bstr *data);
|
||||||
|
|
||||||
|
void *net_server_get_enethost();
|
||||||
|
Loading…
Reference in New Issue
Block a user