CertiFried-TechtonicaDirectConnect icon

TechtonicaDirectConnect

Connect to Techtonica dedicated servers via direct IP. Bypass Steam lobbies and join 24/7 community servers!

CHANGELOG

Changelog

1.0.103

  • FIX: Increased KCP timeout from 10 to 30 seconds
  • Save data transfer was causing disconnects due to main thread blocking during processing
  • Client and server both updated to 30 second timeout for reliable save loading

1.0.102

  • FIX: Fixed tick adjustment condition that never triggered
  • Previous check actionTick < minValidTick failed when minValidTick returned 0 (reflection issue)
  • New check actionTick < currentTick - if action is in the past, adjust to current tick
  • Added debug logging for tick adjustments

1.0.101

  • FIX: Added tick fix for CraftResponse RPC (crafting wasn't working)
  • CraftResponse has signature (NetworkConnection target, CraftInfo info) - info is SECOND argument
  • Added UserCode_Response_Prefix to handle Response methods with different signatures
  • Crafting should now work properly

1.0.100

  • PROPER FIX: Fixed tick synchronization at the source instead of bypassing validation
  • ROOT CAUSE: ProcessCurrentSimTick_Prefix wasn't setting ALL required tick fields
  • Now properly sets _targetTick, _lastSyncTick, _timeToProcess, and curTick on ALL machineManagers
  • TickFixPatches now uses cached reflection for better performance
  • Ticks are adjusted to valid range instead of bypassing validation entirely
  • Actions should now process through normal game code path (proper deterministic simulation)

1.0.99

  • Intermediate test build

1.0.98

  • COMPLETE BYPASS: Now completely bypasses tick validation for dedicated server clients
  • Found root cause: Original code checks _targetTick <= tick which fails because we set ticks directly
  • Actions were being enqueued but never processed because tick validation kept rejecting them
  • New approach: Dequeue actions directly and call ProcessOnClient immediately
  • No more "Can't rewind" errors - actions are processed without any tick checks

1.0.97

  • FIX: HandleEnqueuingClientActions patch was blocking original method execution
  • Changed from bool prefix (skip original) to void prefix (fix ticks then run original)
  • This allows the game's normal action processing to occur after tick fix
  • Actions were being received but not processed - now they should process normally

1.0.96

  • COMPLETE REWRITE: New TickFixPatches.cs to fix tick validation at the source
  • ROOT CAUSE: Found the actual tick validation in FactorySimManager.HandleEnqueuingClientActions()
  • The "Can't rewind" error happens because actions from server have old ticks
  • Previous patches on RPC methods weren't triggering because Mirror invokes differently
  • FIX: Directly patch FactorySimManager.HandleEnqueuingClientActions to fix ticks BEFORE validation
  • Actions with old ticks are now updated to valid ticks instead of being discarded
  • Also patches UserCode_* methods to fix ticks as they're received

1.0.95

  • DEBUG: Added verbose logging to incoming RPC tick fix to diagnose why patches aren't triggering
  • Changed from object[] __args to object __0 for Harmony parameter injection
  • Logs every step of the tick fix process to identify where it's failing

1.0.94

  • CRITICAL FIX: Fixed tick mismatch on INCOMING action broadcasts from server
  • Client now fixes tick on incoming RPCs (HitDestructable, ActivateMachine, etc.) to match client's current tick
  • This prevents "Can't rewind" errors when server tick is behind client tick due to network latency
  • Patches all major incoming action RPC methods with FixIncomingActionTick_Prefix

1.0.93

  • CRITICAL FIX: Fixed tick mismatch "Can't rewind" error that caused all actions to be discarded
  • FIX: The tick field is on the INFO object (e.g., HitDestructibleInfo), not the action itself
  • FixActionTick now correctly sets tick on action.info.tick instead of action.tick
  • FIX: Player lookup now uses multiple methods (Player.instance, NetworkClient.localPlayer, FindObjectOfType)
  • This fixes "Player.instance is null" errors in multiplayer when calculating rewards

1.0.92

  • FIX: Empty server responses no longer trigger "inventory full" error sound
  • NEW: Client now calculates rewards locally when server sends empty response
  • Patches UserCode_HitDestructableResponse to handle headless server empty responses
  • Patches UserCode_HitVoxelResponse, UserCode_MOLEResponse, UserCode_TakeAllResponse
  • Client extracts item rewards from propLookups and adds them to inventory with popups
  • Server-side now sends response to original sender after broadcasting actions

1.0.91

  • Version bump for testing action flow

1.0.87

  • ROOT CAUSE FOUND: Decompiled game code to find the actual bug
  • SendNetworkAction calls Player.instance.networkedPlayer.AddPendingAction(action) BEFORE the switch statement
  • On dedicated server clients, Player.instance is null - causing NullReferenceException before commands are sent
  • FIX: Complete replacement of SendNetworkAction - prefix returns false to skip original method
  • Directly calls the appropriate Command method (TakeAllCommand, HitDestructableCommand, MOLECommand, etc.)
  • Full mapping of all 50+ action types to their Command methods based on decompiled game code
  • All Commands have [Command(requiresAuthority = false)] so they work without authority

1.0.86

  • FIX: Force call CmdSendNetworkAction from postfix patch
  • The original SendNetworkAction method was completing without calling the actual Mirror Command
  • Now the postfix directly invokes CmdSendNetworkAction via reflection to send actions to the server
  • Added detailed logging to show all Command methods on NetworkMessageRelay for debugging
  • This should fix mining, crafting, building, picking up items, MOLE drilling

1.0.72

  • FIX: Fixed "Ambiguous match found" error in HitDestructibleInfo - now uses actual resource type for method lookup
  • FIX: MOLE ore mining now works - prefix sets canMineOre=true so client can determine ore locally
  • FIX: Improved type lookups - now tries CraftActionInfo, SimpleBuildActionInfo, ExchangeMachineActionInfo first
  • FIX: Removed broken fallback code that could throw AmbiguousMatchException
  • Plants and destructibles should now properly drop items to inventory
  • MOLE should now properly mine ore and add to inventory

1.0.63

  • NEW: Added ExchangeMachineInfo handler for single item clicks in storage
  • When clicking individual items in storage, items now properly transfer to player inventory
  • Fixed items disappearing when clicking stacks in storage containers

1.0.62

  • FIX: ResourceStack.info is a PROPERTY, not a field - use GetProperty() instead of GetField()
  • This fixes items showing info=False and not being added to inventory
  • Items taken from machines should now properly appear in player inventory

1.0.61

  • FIX: Use NetworkClient.localPlayer to get Player in multiplayer (Player.instance is null)
  • Try multiple methods: Player.instance, NetworkClient.localPlayer, FindObjectOfType

1.0.60

  • DEBUG: Detailed logging for Player.instance, inventory, and AddResources calls

1.0.59

  • DEBUG: More detailed logging in TakeAll and HitDestructible to trace item retrieval

1.0.58

  • DEBUG: Added logging to TakeAllInfo and HitDestructibleInfo prefixes to diagnose inventory sync

1.0.57

  • NEW: Client-side inventory synchronization for headless server compatibility
  • Patches TakeAllInfo.ProcessOnClient to add items to local inventory when taking from machines
  • Patches HitDestructibleInfo.ProcessOnClient to add drops to inventory when destroying props
  • Stub patches for MOLEActionInfo, CraftCommand, SimpleBuildInfo (future implementation)
  • Uses "trust the client" model since headless server can't calculate inventory changes

1.0.56

  • FIX: Use correct netId=2 for server relay (not 1)
  • Server's spawned dictionary: [1]=Player Cheats, [2]=MachineMessageRelay
  • Client now correctly routes commands to netId=2 where the relay actually is
  • This should finally fix pickup, mining, building, crafting

1.0.55

  • FIX: Force client's relay netId to 1 to match server
  • Client scene relay has netId=2, server relay has netId=1 - commands weren't routing
  • Now fixes netId before sending ANY network action
  • Added debug logging to confirm SendNetworkAction is triggered
  • This should finally fix pickup, mining, building, crafting

1.0.54

  • Version bump to force fresh download (v1.0.53 was getting cached)
  • Same fix as v1.0.53: Add prefix to SendNetworkAction to fix connectionToServer

1.0.53

  • FIX: Add prefix to SendNetworkAction to fix connectionToServer before commands
  • connectionToServer was null on client's NetworkIdentity, preventing all game commands
  • Now sets connectionToServer via reflection before any network action is sent
  • This should fix pickup, mining, building, and crafting

1.0.52

  • CRITICAL FIX: Set NetworkBehaviours array and ComponentIndex on NetworkIdentity
  • Mirror requires NetworkIdentity.NetworkBehaviours array to be populated for RPC routing
  • This is normally done in Awake() by InitializeNetworkBehaviours(), but runtime components miss this
  • Now explicitly sets NetworkBehaviours = [relay] and ComponentIndex = 0 on the relay
  • This fixes "Component [0] not found for [netId=1]" warning
  • Combined with v1.0.51's netIdentity backing field fix, Mirror should now route all RPCs correctly
  • This should enable game interactions (pickup, mine, build, craft, inventory sync)

1.0.51

  • CRITICAL FIX: Manually set netIdentity backing field on NetworkBehaviour
  • When adding NetworkBehaviour components at runtime, Mirror's caching doesn't work
  • Now explicitly sets <netIdentity>k__BackingField on the NetworkMessageRelay
  • This fixes "Object reference not set" errors in SendTargetRPCInternal
  • Server and client both now properly link NetworkIdentity to NetworkBehaviour
  • This should finally fix game interactions (pickup, mine, build, craft)

1.0.50

  • FIX: Server now proactively pushes tick to new clients on connect
  • This bypasses the broken client->server RequestCurrentSimTick command flow
  • Added detailed debug logging for NetworkIdentity state in RequestCurrentSimTick
  • Server's HeadlessPatches now calls ProactivelySendTickToClient when player joins
  • These fixes should enable game interactions (pickup, mine, build, craft)

1.0.49

  • FIX: connectionToServer is a PROPERTY not a field - use GetSetMethod(true) for internal setter
  • This should finally allow commands to be sent to the server

1.0.48

  • FIX: Set connectionToServer on custom NetworkIdentity for Command routing
  • Without this, SendCommandInternal fails with null reference
  • FIX: Patch UserCode_ProcessCurrentSimTick to handle null FactorySimManager
  • Server's tick response now handled gracefully even if game systems aren't initialized
  • Also sets MachineManager.curTick when tick sync is received
  • These fixes should enable game interactions (pickup, mine, build, craft)

1.0.47

  • FIX: Create NetworkMessageRelay with NetworkIdentity if none exists in scene
  • When spawn message arrives before scene loads, now creates a proper relay
  • Links created relay to server's netId (1) for Command routing
  • Sets hasAuthority = true for client-owned commands
  • This should fix interaction (pickup, mine, craft, chest access)

1.0.46

  • FIX: Added NetworkRelayLinkingPatches to fix Command routing
  • Intercepts spawn messages for server's NetworkMessageRelay (netId 1)
  • Links client's scene relay to server's netId so Commands route properly
  • Skips original OnSpawn to prevent "no AssetId" error
  • Server now spawns NetworkMessageRelay to clients

1.0.45

  • FIX: KCP transport DualMode mismatch
  • Client now uses DualMode = false (IPv4 only) to match server
  • Fixes "Client KcpTransport DualMode mismatch" connection errors

1.0.44

  • STATUS: WORKING! Successfully connecting to dedicated servers!
  • Updated README with correct usage instructions
  • Main menu "Join Multiplayer" button now works
  • F11 hotkey works from anywhere
  • Connects from main menu without loading a save first

1.0.43

  • FIX: Don't disable LoadingUI gameObject (broke save loading)
  • Now only hides visually with alpha=0 but keeps gameObject active
  • Creates dummy NetworkMessageRelay instance to prevent NRE in FlowManager
  • This should allow the loading process to complete naturally

1.0.42

  • FIX: Force-hide loading screen by disabling the gameObject entirely
  • Sets CanvasGroup alpha to 0 (invisible)
  • Sets blocksRaycasts to false (clicks pass through)
  • Disables LoadingUI gameObject completely
  • This bypasses the "press any key" input requirement

1.0.41

  • FIX: Bypass "Click to continue" entirely after forcing loading completion
  • Sets confirmedLoad = true to skip the click requirement
  • Sets _loaded = true to mark loading as complete
  • Ensures CanvasGroup is interactable (in case that was blocking clicks)
  • Should now go directly to game after 3 seconds without needing to click

1.0.40

  • FIX: Restore Time.timeScale to 1 after forcing loading completion
  • Game sets timeScale=0 during loading, which also freezes input
  • Now properly restores timeScale so "Click to continue" works!

1.0.39

  • FIX: Use Time.unscaledDeltaTime instead of Time.deltaTime
  • Game sets timeScale=0 during loading, making deltaTime=0
  • unscaledDeltaTime ignores timeScale and works during loading!
  • Timer should now properly increment and trigger OnFinishLoading after 3 seconds

1.0.38

  • DEBUG: Added timer increment debug logging
  • Shows before/after values and deltaTime to confirm increment is happening
  • This will tell us if Time.deltaTime is 0 or if timer is being reset

1.0.37

  • FIX: Moved timer increment outside else block
  • Timer now increments every frame when isActive=true (not just when monitorActive=true)
  • Added deltaTime to progress log for debugging
  • This should fix the timer not incrementing issue

1.0.36

  • DEBUG: Changed isActive detection to use _loaded field
  • Now checks: gameObject active AND _loaded==false (still loading)
  • Added logging every 60 frames showing goActive, _loaded, isActive, timer
  • This will show why the timer keeps resetting

1.0.35

  • DEBUG: Added HEARTBEAT log every 5 seconds in Update()
  • Shows frame count, monitor state, timer, and finishCalled status
  • This will confirm if Update() is still running after the NRE

1.0.34

  • DEBUG: Added logging at every exit point in CheckLoadingMonitor
  • Logs when NetworkClient becomes inactive
  • Logs when LoadingUI instance becomes null
  • Logs when loading screen becomes inactive
  • Always logs exceptions (not suppressed)

1.0.33

  • DEBUG: Improved logging frequency (every second instead of every 2)
  • Added logging when loading screen becomes INACTIVE (to understand why monitor stops)
  • Reduced timeout to 3 seconds (was 5)
  • Fixed second-tracking logic for progress logs

1.0.32

  • DEBUG: Added comprehensive logging to loading monitor
  • Tries multiple ways to find LoadingUI instance (field, property, FindObjectOfType)
  • Lists all available fields/methods when reflection fails
  • Logs loading progress every 2 seconds
  • Starts monitoring immediately when loading screen is active (not waiting for specific state)

1.0.31

  • FIX: Fixed AccessTools.Property -> AccessTools.Field for LoadingUI.instance
  • LoadingUI.instance is a field, not a property - was causing reflection to fail
  • Both TryCallOnFinishLoading() and CheckLoadingMonitor() now use correct reflection
  • Updated version in PluginInfo to match package version

1.0.30

  • FIX: Added loading monitor that detects stuck loading screen
  • Automatically calls LoadingUI.OnFinishLoading() after 5 seconds if stuck on "Generating Machines"
  • Properly handles NullReferenceException in NetworkMessageRelay.instance (dedicated server mode)
  • Monitor runs in Update() to catch the issue regardless of where the NRE occurs

1.0.29

  • Added RequestCurrentSimTick_Prefix to handle null NetworkMessageRelay.instance
  • Added RequestCurrentSimTick_Finalizer to catch exceptions and complete loading
  • Calls LoadingUI.OnFinishLoading() directly when server doesn't have NetworkMessageRelay

1.0.26

  • CRITICAL FIX: Removed NetworkedPlayer patches that were breaking save sync!
  • Client was skipping OnStartLocalPlayer which prevented RequestInitialSaveData() from being called
  • Server was never receiving the client's request for world data (causing "Timing out for strata")
  • Now properly receives save/world data from server

1.0.25

  • CRITICAL FIX: Set NetworkManager.networkAddress BEFORE calling JoinGameAsClient
  • The game was trying to connect but didn't know where (caused timeout)
  • Removed redundant ConnectAfterSceneLoad coroutine - game handles connection internally

1.0.24

  • Patched FizzyFacepunch (Steam transport) to prevent NullReferenceException spam
  • Disabled FizzyFacepunch.ClientEarlyUpdate/ClientLateUpdate/ServerEarlyUpdate/ServerLateUpdate
  • Enables KCP transport before calling JoinGameAsClient to prevent Steam transport errors
  • Now works without Steam networking active!

1.0.23

  • Fixed FlowManager.JoinGameAsClient call - now calls it directly instead of via reflection
  • Properly loads game scenes when connecting from main menu
  • Removed unnecessary instance check that was causing "FlowManager.instance is null" error

1.0.22

  • NEW: "Join Multiplayer" button in main menu! Uses the game's hidden button (no more F11 required)
  • Patched MainMenuUI.RefreshHiddenButtonState to show the multiplayer button
  • Patched MainMenuUI.JoinMultiplayerAsClient to show our connection dialog
  • Added Assembly-CSharp reference for direct game type access
  • F11 hotkey still works as a fallback

1.0.21

  • Added join-from-main-menu support using FlowManager.JoinGameAsClient
  • Pressing F11 and Connect from main menu now automatically loads game scenes
  • Added DoConnect helper to reduce code duplication
  • Added ConnectAfterSceneLoad and WaitForGameWorldAndConnect coroutines
  • No longer requires loading a save first - connects like joining a friend!

1.0.20

  • Added patch for NetworkMessageRelay.SendNetworkAction
  • Suppresses NullReferenceException when quest system tries to send network actions
  • Fixes error spam when playing in single player before connecting

1.0.19

  • Fixed crash when connecting from main menu
  • Simplified scene detection - just warns user instead of trying auto-load
  • Clear message: "Load a game first, then press F11"

1.0.18

  • Added scene detection - checks if you're in game world before connecting
  • Logs all loaded scenes for debugging

1.0.17

  • Added patches for NetworkedPlayer.OnStartClient() and OnStartLocalPlayer()
  • These methods crash when connecting because the player spawns before scene objects exist
  • Now patches 5 methods total to prevent NullReferenceException spam

1.0.16

  • Added null safety patches to prevent error spam when connecting
  • Patches NetworkedPlayer.Update() to skip (prevents NullReferenceException)
  • Patches ThirdPersonDisplayAnimator.Update() to skip (prevents NullReferenceException)
  • Patches ThirdPersonDisplayAnimator.UpdateSillyStuff() to skip (prevents NullReferenceException)
  • These errors occurred because the game creates player objects before they're fully initialized

1.0.15

  • Added NetworkClient.Ready() call after connection
  • Added NetworkClient.AddPlayer() to request player spawning
  • Increased connection timeout to 15 seconds
  • Added detailed logging for connection/ready/spawn sequence

1.0.14

  • Fixed double-toggle bug (OnGUI is called multiple times per frame)
  • Added frame guard to ensure UI only toggles once per key press
  • Event.current now properly detected and working!

1.0.13

  • Complete rewrite following ConsoleCommands mod pattern
  • Update/OnGUI now run directly on plugin (like working mods)
  • Added [BepInProcess("Techtonica.exe")] attribute
  • Added HideFlags.HideAndDontSave to persist gameObject
  • Triple input detection: Unity Input, Windows API, and Event.current
  • Removed separate MonoBehaviour (was not initializing properly)

1.0.12

  • Added robust logging for DirectConnectBehaviour lifecycle (Awake, Start)
  • Added fallback F11 detection via Unity's Event.current in OnGUI
  • Added error handling to prevent silent failures
  • Fixed potential null reference issues in Update/OnGUI

1.0.11

  • Updated changelog with all version history

1.0.10

  • Updated mod icon

1.0.9

  • Fixed Update/OnGUI not being called by creating dedicated MonoBehaviour
  • Changed keybind from F8 to F11 (F1-F10 are used in-game)

1.0.8

  • Added debug logging to diagnose input detection issues

1.0.7

  • Added CHANGELOG.md to package

1.0.6

  • Attempted changelog fix

1.0.5

  • Fixed input detection for games using Rewired input system
  • Now uses Windows API (GetAsyncKeyState) to detect key presses
  • Works regardless of game's input system

1.0.4

  • Added alternative input detection via OnGUI events
  • Added debug logging for UI toggle

1.0.3

  • Version bump to force Thunderstore cache refresh

1.0.2

  • Added missing kcp2k.dll dependency (fixes mod not loading)

1.0.1

  • Updated README with server hosting information
  • Fixed GitHub repository links

1.0.0

  • Initial release
  • Direct IP connection to Techtonica dedicated servers
  • In-game UI with F8 hotkey
  • KCP transport for reliable UDP connections
  • Auto-saves last connected server