-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsneeder.go
180 lines (152 loc) · 3.68 KB
/
sneeder.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package main
/*
// Internal Use Stuff
void GoRuntimeHasFullyLoaded(void);
*/
import "C"
import (
"fmt"
"log"
"runtime"
"sync"
"time"
. "gtasamod/madresser"
. "gtasamod/types"
)
// Used for rundll32 dry testing
//
//export Ccalls
func Ccalls() {
fmt.Println("go called from c")
}
func init() {
//fmt.Println("go init called")
C.GoRuntimeHasFullyLoaded()
}
//export GODLLmain
func GODLLmain() {
// After going from init() -> C.GoRuntimeHasFullyLoaded -> GODLLmain,
// we kick off our main "thread" now that we know 100% everything is
// taken care of in terms of loading.
go main()
}
// Called by GODLLmain, or normally when not being a dll
func main() {
/*
// Useful for analysation
go func() {
for {
time.Sleep(30 * time.Second)
dumpStackTraces()
}
}()
*/
setupLogging()
// we need to wait here so windows can fully load the main exe,
// otherwise we will silently fail and exit. This variable will
// be not zero once the game starts starting, after which we can
// do our hooks.
dxptr := TypeAtAbsolute[uint32](0xC97C28) //pointer to IDirect3DDevice9
for {
if *dxptr != 0 {
break
}
runtime.Gosched()
}
SetupFunctionsHooks() // gtasa_functionhooks.go
select {
//Block until we get unloaded. Maybe do something useful here.
}
}
type GameInternals struct {
player *CPlayer
wanted *CWanted
currentvehicle **CVehicle
}
// For GameFunc:
// return true to run again next iteration
// return false to get removed from the run queue
// also just return false if you want to run it once
type GameFunc func(*GameInternals) bool
var extfuncs []GameFunc
var extfuncsmutex sync.Mutex
func AddFn(fn GameFunc) {
extfuncsmutex.Lock()
extfuncs = append(extfuncs, fn)
extfuncsmutex.Unlock()
}
//fixme todo:
// Might be intersting to do something with it
// 0xB73458 – Start of controls block.
// +0x20 = [word] Accelerate:
// 0 = off
// 255 = on
// +0x22 = [word] Brake
// https://gtamods.com/wiki/Memory_Addresses_(SA)
var gameInternals GameInternals
var gamehasinit bool
// We use this to initialise everything we need once on the first
// ingame frame, and then rewire the call to the bare function.
//
//export RenderSceneFirstGo
func RenderSceneFirstGo() {
//log.Println("Ingame Render")
if gamehasinit {
log.Println("if you see this every frame it didnt rehook correctly to the more efficient function")
}
gameInternals = GameInternals{
// the player struct is store there
player: TypeAtAbsolute[CPlayer](0xB7CD98),
wanted: *TypeAtAbsolute[*CWanted](0xB7CD9C),
//0xBA18FC – Current vehicle pointer:
// 0 = on-foot
// >0 = in-car
currentvehicle: TypeAtAbsolute[*CVehicle](0xBA18FC),
}
gamehasinit = true
go launchWeb(&gameInternals)
// rewire this call to RenderSceneGo
SetRenderFuncLooping()
// run the custom functions here, afterwards
// that function will be fun directly
RenderSceneGo()
}
// This is the bare function the other comment talked about.
//
//export RenderSceneGo
func RenderSceneGo() {
i := 0
extfuncsmutex.Lock()
for _, fn := range extfuncs {
if fn(&gameInternals) {
extfuncs[i] = fn
i++
}
}
extfuncs = extfuncs[:i]
extfuncsmutex.Unlock()
}
var quitfuncs []func()
var quitfuncsmutex sync.Mutex
func AddQuitFn(fn func()) {
quitfuncsmutex.Lock()
quitfuncs = append(quitfuncs, fn)
quitfuncsmutex.Unlock()
}
//export GameIsQuitting
func GameIsQuitting() {
log.Println("Game is quitting")
for _, fn := range quitfuncs {
fn()
}
time.Sleep(1 * time.Second)
dumpStackTraces()
}
//export TypedChars
func TypedChars(c uint32, pinputting *bool) bool {
// We only care about input after we are fully loaded
if !gamehasinit {
return false
}
return Menuhandler(c, pinputting)
}