<commit_before>package mouse

import (
	"errors"

	"github.com/oakmound/oak/v3/collision"
	"github.com/oakmound/oak/v3/event"
)

// CollisionPhase is a component that can be placed into another struct to
// enable PhaseCollision on the struct. See PhaseCollision.
type CollisionPhase struct {
	OnCollisionS *collision.Space
	LastEvent    *Event

	wasTouching bool
}

func (cp *CollisionPhase) getCollisionPhase() *CollisionPhase {
	return cp
}

type collisionPhase interface {
	getCollisionPhase() *CollisionPhase
}

// PhaseCollision binds to the entity behind the space's CID so that it will
// receive MouseCollisionStart and MouseCollisionStop events, appropriately when
// the mouse begins to hover or stops hovering over the input space.
func PhaseCollision(s *collision.Space) error {
	en := s.CID.E()
	if cp, ok := en.(collisionPhase); ok {
		oc := cp.getCollisionPhase()
		oc.OnCollisionS = s
		s.CID.Bind(event.Enter, phaseCollisionEnter)
		return nil
	}
	return errors.New("This space's entity does not implement collisionPhase")
}

// MouseCollisionStart/Stop: see collision Start/Stop, for mouse collision
// Payload: (*mouse.Event)
const (
	Start = "MouseCollisionStart"
	Stop  = "MouseCollisionStop"
)

func phaseCollisionEnter(id event.CID, nothing interface{}) int {
	e := id.E().(collisionPhase)
	oc := e.getCollisionPhase()

	// TODO: think about how this can more cleanly work with multiple controllers
	ev := oc.LastEvent
	if ev == nil {
		ev = &LastEvent
	}
	if ev.StopPropagation {
		return 0
	}

	if oc.OnCollisionS.Contains(ev.ToSpace()) {
		if !oc.wasTouching {
			id.Trigger(Start, ev)
			oc.wasTouching = true
		}
	} else {
		if oc.wasTouching {
			id.Trigger(Stop, ev)
			oc.wasTouching = false
		}
	}
	return 0
}<commit_msg>mouse/collision: Update collisionenter to have an extra sanity check for instances where unintended collisionspaces without a real space underneath them dont panic<commit_after>package mouse

import (
	"errors"

	"github.com/oakmound/oak/v3/collision"
	"github.com/oakmound/oak/v3/event"
)

// CollisionPhase is a component that can be placed into another struct to
// enable PhaseCollision on the struct. See PhaseCollision.
type CollisionPhase struct {
	OnCollisionS *collision.Space
	LastEvent    *Event

	wasTouching bool
}

func (cp *CollisionPhase) getCollisionPhase() *CollisionPhase {
	return cp
}

type collisionPhase interface {
	getCollisionPhase() *CollisionPhase
}

// PhaseCollision binds to the entity behind the space's CID so that it will
// receive MouseCollisionStart and MouseCollisionStop events, appropriately when
// the mouse begins to hover or stops hovering over the input space.
func PhaseCollision(s *collision.Space) error {
	en := s.CID.E()
	if cp, ok := en.(collisionPhase); ok {
		oc := cp.getCollisionPhase()
		oc.OnCollisionS = s
		s.CID.Bind(event.Enter, phaseCollisionEnter)
		return nil
	}
	return errors.New("This space's entity does not implement collisionPhase")
}

// MouseCollisionStart/Stop: see collision Start/Stop, for mouse collision
// Payload: (*mouse.Event)
const (
	Start = "MouseCollisionStart"
	Stop  = "MouseCollisionStop"
)

func phaseCollisionEnter(id event.CID, nothing interface{}) int {
	e := id.E().(collisionPhase)
	oc := e.getCollisionPhase()
	if oc == nil || oc.OnCollisionS == nil {
		return 0
	}

	// TODO: think about how this can more cleanly work with multiple controllers
	ev := oc.LastEvent
	if ev == nil {
		ev = &LastEvent
	}
	if ev.StopPropagation {
		return 0
	}

	if oc.OnCollisionS.Contains(ev.ToSpace()) {
		if !oc.wasTouching {
			id.Trigger(Start, ev)
			oc.wasTouching = true
		}
	} else {
		if oc.wasTouching {
			id.Trigger(Stop, ev)
			oc.wasTouching = false
		}
	}
	return 0
}
{'fraction_non_alphanumeric': 0.10043080236941303, 'fraction_numerical': 0.0024232633279483036, 'mean_word_length': 4.047554347826087, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7208066', 'n_tokens_mistral': 1279, 'n_tokens_neox': 1223, 'n_words': 366}