174 lines
3.7 KiB
Go
174 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/google/subcommands"
|
|
buttplug "github.com/pidurentry/buttplug-go"
|
|
"github.com/sandertv/gophertunnel/minecraft"
|
|
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
|
)
|
|
|
|
type BpCMD struct {
|
|
server_address string
|
|
buttplugIP string
|
|
dev buttplug.DeviceManager
|
|
}
|
|
|
|
func (*BpCMD) Name() string { return "bpio" }
|
|
func (*BpCMD) Synopsis() string { return "buttplug.io intigration" }
|
|
|
|
func (c *BpCMD) SetFlags(f *flag.FlagSet) {
|
|
f.StringVar(&c.server_address, "address", "", "remote server address")
|
|
f.StringVar(&c.buttplugIP, "bpaddr", "192.168.178.50", "other address")
|
|
}
|
|
func (c *BpCMD) Usage() string {
|
|
return c.Name() + ": " + c.Synopsis() + "\n"
|
|
}
|
|
|
|
func (c *BpCMD) Execute(ctx context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus {
|
|
fmt.Println("connecting to buttplug server")
|
|
bp, err := buttplug.Dial(fmt.Sprintf("ws://%s:12345", c.buttplugIP))
|
|
if err != nil {
|
|
fmt.Fprintf(os.Stderr, "buttplug connect error: %s\n", err)
|
|
}
|
|
handler := buttplug.NewHandler(bp)
|
|
device_manager := buttplug.NewDeviceManager(handler)
|
|
c.dev = device_manager
|
|
|
|
scan := c.dev.Scan(30 * time.Second)
|
|
fmt.Println("Scanning for devices...")
|
|
go func() {
|
|
scan.Wait()
|
|
fmt.Println("Stopped scanning")
|
|
fmt.Println("Found: (")
|
|
for _, d := range c.dev.Devices() {
|
|
fmt.Printf("\t%s\n", d.DeviceName())
|
|
}
|
|
fmt.Println(")")
|
|
}()
|
|
|
|
address, _, err := server_input(c.server_address)
|
|
if err != nil {
|
|
fmt.Fprint(os.Stderr, err)
|
|
return 1
|
|
}
|
|
|
|
listener, clientConn, serverConn, err := create_proxy(ctx, address)
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return 1
|
|
}
|
|
defer listener.Close()
|
|
|
|
println("Connected")
|
|
|
|
type vib struct {
|
|
v buttplug.Vibrate
|
|
end time.Time
|
|
}
|
|
|
|
vibrates := make(map[string]vib)
|
|
vib_mutex := &sync.Mutex{}
|
|
|
|
go func() {
|
|
for {
|
|
now := time.Now()
|
|
var to_clear []string
|
|
vib_mutex.Lock()
|
|
for name, v := range vibrates {
|
|
if now.After(v.end) {
|
|
fmt.Println("stopping vibrate")
|
|
v.v.Stop()
|
|
to_clear = append(to_clear, name)
|
|
}
|
|
}
|
|
for _, v := range to_clear {
|
|
delete(vibrates, v)
|
|
}
|
|
vib_mutex.Unlock()
|
|
time.Sleep(1 * time.Second)
|
|
}
|
|
}()
|
|
|
|
vibrate_ms := func(v buttplug.Vibrate, ms int) {
|
|
vib_mutex.Lock()
|
|
var name string = string(v.DeviceName())
|
|
t := time.Now()
|
|
if v_e, ok := vibrates[name]; ok {
|
|
t = v_e.end
|
|
}
|
|
vibrates[name] = vib{
|
|
v: v,
|
|
end: t.Add(time.Duration(ms) * time.Millisecond),
|
|
}
|
|
vib_mutex.Unlock()
|
|
}
|
|
|
|
errs := make(chan error, 2)
|
|
go func() { // server -> client
|
|
defer serverConn.Close()
|
|
defer listener.Disconnect(clientConn, "connection lost")
|
|
for {
|
|
pk, err := serverConn.ReadPacket()
|
|
if err != nil {
|
|
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
|
|
_ = listener.Disconnect(clientConn, disconnect.Error())
|
|
}
|
|
return
|
|
}
|
|
|
|
if err = clientConn.WritePacket(pk); err != nil {
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
go func() { // client -> server
|
|
for {
|
|
pk, err := clientConn.ReadPacket()
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
switch pk := pk.(type) {
|
|
case *packet.Animate:
|
|
if pk.ActionType == packet.AnimateActionSwingArm {
|
|
devs := device_manager.Vibrators()
|
|
fmt.Printf("vibrating %d devices\n", len(devs))
|
|
for _, v := range devs {
|
|
vibrate_ms(v, 1000)
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := serverConn.WritePacket(pk); err != nil {
|
|
if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok {
|
|
_ = listener.Disconnect(clientConn, disconnect.Error())
|
|
}
|
|
return
|
|
}
|
|
}
|
|
}()
|
|
|
|
for {
|
|
select {
|
|
case err := <-errs:
|
|
fmt.Fprintln(os.Stderr, err)
|
|
return 1
|
|
case <-ctx.Done():
|
|
return 0
|
|
}
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
register_command(&BpCMD{})
|
|
}
|