Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin node #109

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions content.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ func muxNodeDefs(conns []*contentConn) (nodeDefs []mt.NodeDef, p0Map param0Map,
}

def.Param0 = param0
oldName := def.Name // copy string to use later
prepend(cc.mediaPool, &def.Name)
prepend(cc.mediaPool, &def.Mesh)
for i := range def.Tiles {
Expand All @@ -456,6 +457,9 @@ func muxNodeDefs(conns []*contentConn) (nodeDefs []mt.NodeDef, p0Map param0Map,
if param0 >= mt.Unknown && param0 <= mt.Ignore {
param0 = mt.Ignore + 1
}

// add nodeid (if reqested)
addNodeId(oldName, def.Param0)
}
}

Expand Down
76 changes: 76 additions & 0 deletions plugin_map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package proxy

import (
"sync"

"github.com/anon55555/mt"
)

type BlkDataHandler struct {
UsePos bool // if set, filters by BlkPos in Pos
Pos [3]int16 // ^ specifies BlkPos when UsePos is set
Handler func(*ClientConn, *mt.ToCltBlkData) bool
}

var blkDataHandlers []BlkDataHandler
var blkDataHandlersMu sync.RWMutex

var cacheNodes = map[string]map[mt.Content]bool{}
var cacheNodesMu sync.RWMutex

// RegisterCacheNode tells server, that nodename is suppost to be cached
func RegisterCacheNode(nodename string) {
cacheNodesMu.Lock()
defer cacheNodesMu.Unlock()

if cacheNodes[nodename] == nil {
cacheNodes[nodename] = map[mt.Content]bool{} // default value, empty map
}
}

// GetNodeId gets the nodeid of a
// If not registerd returns map[mt.Content]bool{}
func GetNodeId(nodename string) map[mt.Content]bool {
cacheNodesMu.RLock()
defer cacheNodesMu.RUnlock()

if cacheNodes[nodename] != nil {
return cacheNodes[nodename]
} else {
return nil
}
}

// addNodeId sets node id, if allready set, ignore
func addNodeId(nodename string, id mt.Content) {
cacheNodesMu.Lock()
defer cacheNodesMu.Unlock()

if cacheNodes[nodename] != nil {
cacheNodes[nodename][id] = true
}
}

// RegisterBlkDataHandler registers a BlkDataHande
func RegisterBlkDataHandler(handler BlkDataHandler) {
blkDataHandlersMu.Lock()
defer blkDataHandlersMu.Unlock()

blkDataHandlers = append(blkDataHandlers, handler)
}

func handleBlkData(cc *ClientConn, cmd *mt.ToCltBlkData) bool {
blkDataHandlersMu.RLock()
defer blkDataHandlersMu.RUnlock()

handled := false
for _, handler := range blkDataHandlers {
if !handler.UsePos && handler.Handler(cc, cmd) {
handled = true
} else if handler.Pos == cmd.Blkpos && handler.Handler(cc, cmd) {
handled = true
}
}

return handled
}
176 changes: 176 additions & 0 deletions plugin_node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
package proxy

import (
"sync"

"github.com/anon55555/mt"
)

type NodeHandler struct {
Node string
nodeIds map[mt.Content]bool
OnDig func(*ClientConn, *mt.ToSrvInteract) bool
OnStopDigging func(*ClientConn, *mt.ToSrvInteract) bool
OnDug func(*ClientConn, *mt.ToSrvInteract) bool
OnPlace func(*ClientConn, *mt.ToSrvInteract) bool // TODO IMPLEMENTED
}

var nodeHandlers []*NodeHandler
var nodeHandlersMu sync.RWMutex

var mapCache map[[3]int16]*[4096]mt.Content
var mapCacheMu sync.RWMutex
var mapCacheOnce sync.Once

func initMapCache() {
mapCacheOnce.Do(func() {
mapCache = map[[3]int16]*[4096]mt.Content{}
})
}

func RegisterNodeHandler(handler *NodeHandler) {
nodeHandlersMu.Lock()
defer nodeHandlersMu.Unlock()

RegisterCacheNode(handler.Node)
nodeHandlers = append(nodeHandlers, handler)
}

func initNodeHandlerNodeIds() {
nodeHandlersMu.RLock()
defer nodeHandlersMu.RUnlock()

for _, h := range nodeHandlers {
if h.nodeIds == nil {
id := GetNodeId(h.Node)

if id != nil {
h.nodeIds = id
}
}
}
}

func GetMapCache() map[[3]int16]*[4096]mt.Content {
initMapCache()

mapCacheMu.RLock()
defer mapCacheMu.RUnlock()

return mapCache
}

func IsCached(pos [3]int16) bool {
initMapCache()

mapCacheMu.RLock()
defer mapCacheMu.RUnlock()

blkpos, i := mt.Pos2Blkpos(pos)
if mapCache[blkpos] == nil {
return false
} else {
return mapCache[blkpos][i] != 0
}
}

func handleNodeInteraction(cc *ClientConn, pointedNode *mt.PointedNode, cmd *mt.ToSrvInteract) bool {
nodeHandlersMu.RLock()
defer nodeHandlersMu.RUnlock()

mapCacheMu.RLock()
defer mapCacheMu.RUnlock()

var handled bool
for _, handler := range nodeHandlers {
// check if nodeId is right
pos, i := mt.Pos2Blkpos(pointedNode.Under)
if handler.nodeIds[mapCache[pos][i]] {
var h bool

switch cmd.Action {
case mt.Dig:
if handler.OnDig != nil {
h = handler.OnDig(cc, cmd)
}
case mt.StopDigging:
if handler.OnStopDigging != nil {
h = handler.OnStopDigging(cc, cmd)
}
case mt.Dug:
if handler.OnDug != nil {
h = handler.OnDug(cc, cmd)
}
case mt.Place:
if handler.OnPlace != nil {
h = handler.OnPlace(cc, cmd)
}
}

if h {
handled = h
}
}
}

return handled
}

func initPluginNode() {
RegisterBlkDataHandler(BlkDataHandler{
Handler: func(cc *ClientConn, cmd *mt.ToCltBlkData) bool {
initMapCache()
initNodeHandlerNodeIds()

mapCacheMu.Lock()
defer mapCacheMu.Unlock()

for i, node := range cmd.Blk.Param0 {
// check if node is interesting
interesting := false
for _, h := range nodeHandlers {
if h.nodeIds[node] {
interesting = true
break
}
}

// if it changed
if !interesting {
if mapCache[cmd.Blkpos] != nil {
if mapCache[cmd.Blkpos][i] != 0 && mapCache[cmd.Blkpos][i] != node {
interesting = true
}
}
}

if interesting {
if mapCache[cmd.Blkpos] == nil {
mapCache[cmd.Blkpos] = &[4096]mt.Content{}
}
mapCache[cmd.Blkpos][i] = node
}
}

return false
},
})

RegisterInteractionHandler(InteractionHandler{
Type: AnyInteraction,
Handler: func(cc *ClientConn, cmd *mt.ToSrvInteract) bool {
handled := false

if pointedNode, ok := cmd.Pointed.(*mt.PointedNode); ok {
if IsCached(pointedNode.Under) {
// is a interesting node
if handleNodeInteraction(cc, pointedNode, cmd) {
handled = true
}
}
}

return handled
},
})
}
4 changes: 4 additions & 0 deletions process.go
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,10 @@ func (sc *ServerConn) process(pkt mt.Pkt) {
}
sc.prependInv(cmd.Blk.NodeMetas[k].Inv)
}

if handleBlkData(sc.client(), cmd) {
return
}
case *mt.ToCltAddNode:
sc.globalParam0(&cmd.Node.Param0)
case *mt.ToCltAddParticleSpawner:
Expand Down
3 changes: 3 additions & 0 deletions run.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ func runFunc() {

log.Println("listen", l.Addr())

// plugin_node.go
initPluginNode()

go func() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
Expand Down